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.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.