Secret Scan Sweep
Weekly flow runs Search GitHub Using Query across the org for risky patterns (AKIA*, password=, private_key), logs hits to Dataverse, and emails Security Team links to matches for remediation.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
A weekly scheduled Power Automate cloud flow that scans every repository in a configurable GitHub organization for risky secret-leak patterns (e.g., AKIA, password=, private_key, BEGIN RSA PRIVATE KEY, Slack bot tokens, api_key=, client_secret=), logs each match to a Dataverse table, and emails the security team an HTML summary table with direct links for triage.
The flow is a complete reference implementation. It ships in the Off state — turning it on requires only (a) authorizing the GitHub PAT and Office 365 + Dataverse connections in the default environment, and (b) setting the four environment variables listed below.
Use Case
Continuous, low-touch secret-leak auditing for a GitHub organization — without the cost or procurement delay of a dedicated secret-scanning SaaS. Ideal for small-to-mid security teams who need an auditable log of pattern matches in Dataverse plus a weekly digest in Outlook.
The flow is ideal for teams that:
- Small-to-mid security teams needing an auditable log of pattern matches in Dataverse
- Organizations wanting a weekly digest of potential secret leaks in Outlook
- Teams looking to avoid the cost or procurement delay of a dedicated secret-scanning SaaS
Flow Architecture
Every_Monday_At_8AM
RecurrenceWeek/1, Monday 08:00 UTC. Weekly cadence avoids GitHub code-search rate limits while keeping the signal fresh enough for routine triage.
Init_varGitHubOrg
Initialize variableBinds `flowlibs_GitHubOrganization` to a local string variable.
Init_varGitHubPAT
Initialize variableBinds `flowlibs_GitHubPAT` to a local string variable. The PAT is hydrated into a variable first and concatenated into the Authorization header at runtime to avoid Flow Checker flagging a direct env-var-in-header leak.
Init_varSecretScanPatterns
Initialize variableBinds `flowlibs_SecretScanPatterns` (comma-separated list) to a local string variable.
Init_varHitTable
Initialize variableBinds `flowlibs_SecretScanHitTable` (entity-set name, documentation-only) to a local string.
Init_varSecurityTeamEmail
Initialize variableBinds `flowlibs_SecurityTeamEmail` to a local string variable.
Init_varScanRunId
Initialize variableInitializes a unique run id via `@guid()` so all hits from a single scan can be correlated after the fact.
Init_varTotalHits
Initialize variableInteger counter, starts at 0.
Init_varHitRowsHtml
Initialize variableString accumulator for the email body rows.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_GitHubOrganization | String | flowlibs-demo-org | GitHub organization login to scan. |
| flowlibs_GitHubPAT | String | <configure> | GitHub Personal Access Token with read access (code search scope). Must be set at activation. |
| flowlibs_SecretScanPatterns | String | AKIA,password=,private_key,BEGIN RSA PRIVATE KEY,xoxb-,api_key=,client_secret= | Comma-separated list of literal strings to search for via GitHub code search. |
| flowlibs_SecretScanHitTable | String | flowlibs_secretscanhits | Dataverse entity-set name for the hit log. Documentation-only — the flow hardcodes this set name in the Dataverse CreateRecord action to avoid Flow Checker "Row Item is required" false positives from variable-driven entity names. |
| flowlibs_SecurityTeamEmail | String | securityteam@your-tenant.onmicrosoft.com | Recipient for the weekly summary email. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Microsoft Dataverse | shared_commondataserviceforapps | CreateRecord (Creates a row in flowlibs_secretscanhits for each match) |
| Office 365 Outlook | shared_office365 | SendEmailV2 (Weekly summary email to the security team) |
| HTTP (built-in) | http | GET https://api.github.com/search/code (Authed via PAT header; built-in fallback (no native GitHub code-search operation)) |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Narrow or expand the scan
- Edit flowlibs_SecretScanPatterns. Add project-specific markers (e.g., company API-key prefixes like int_, sk_live_, GitHub app private-key markers) or remove ones that produce too much noise. Patterns are matched exactly as provided, with commas as the only separator.
- Change the cadence
- Edit the Recurrence trigger. Daily works well for fast-moving orgs; weekly is the default to keep the signal-to-noise ratio manageable.
- Switch recipient
- Edit flowlibs_SecurityTeamEmail. For a distribution list, use the group's SMTP address.
- Additional downstream routing
- Insert a Condition after the summary email that checks @greater(variables('varTotalHits'), 0) and triggers a Teams message to a Security channel or a Dataverse-backed incident record in high-hit scenarios.
- Retain history trimming
- Add a monthly cleanup flow that queries flowlibs_secretscanhits with scandate lt {n} days ago and deletes stale rows via shared_commondataserviceforapps/DeleteRecord, if regulatory retention permits.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Init_varScanRunId
Unique run id to correlate every hit from a single scan run.
EXPR.02Compose_PatternArray
Splits the comma-separated patterns env var into an array for the For_Each_Pattern loop.
EXPR.03Search_Code_In_Organization URI
Builds the GitHub code-search URL per pattern, URL-encoding the pattern and scoping by org.
EXPR.04Search_Code_In_Organization Authorization header
PAT is concatenated into the Authorization header at runtime (env var is read into varGitHubPAT first to avoid Flow Checker flags).
EXPR.05For_Each_Hit foreach
Defensive iteration: coalesces a missing `items` array to an empty array so the loop is a no-op when there are no hits.
EXPR.06Compose_Email_Body conditional color
Renders the total-hits number in red when greater than zero, green when zero.
Customize & download
Generate a ready-to-import copy of this solution with your environment-variable values baked in — available on Base, Pro, or Team.
Upgrade to customize
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.