Track leaked GitHub secrets in Port
Send this guide to your coding agent.
Prerequisite: Install Port MCP
Open plan mode if your tool supports it; otherwise present the plan below filled in and wait for my approval. Implement this Port guide in my org via MCP: https://docs.port.io/guides/all/track-leaked-github-secrets-in-port Read the raw markdown version at https://docs.port.io/guides/all/track-leaked-github-secrets-in-port.md - it contains every tab and code block without page markup. Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1. Plan: 1. Confirm MCP is connected, in the right org, with sufficient permissions. 2. If the guide offers alternative implementation paths (tabs), pick the one matching my installed integrations and tools, confirm it with me, and implement only that path. 3. Diff the guide's data model (blueprints, properties, relations, workflows, actions, agents, automations, integrations, webhook data sources, secrets) against mine. 4. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates. 5. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out. If the guide has a "Set up via API" section, use it for anything MCP can't do before treating a step as UI-only. 6. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed. Build: - Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix. - Never print secret values into the chat or logs; ask me to set them in Port, or write them via the secrets API without echoing them back. - List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded. - For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock. - For pages/widgets, use the real page identifier from the app URL, not a guessed slug. - When you hit a UI step confirmed (not assumed) unsupported via MCP and not covered by the guide's API sections, pause, give exact clicks, then resume via MCP. - Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success. Done: - Run the guide's "Let's test it" steps where possible (e.g. execute a workflow test run) and confirm the expected output exists in Port. - Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.
This guide demonstrates how to set up a webhook integration between GitHub and Port to automatically detect and ingest leaked application secrets. You will learn how to use Gitleaks to scan your repositories for secrets and send the results to Port for centralized monitoring and management.
Common use cases
- Automatically detect and track leaked secrets across your repositories.
- Centralize security monitoring and incident response for credential leaks.
Prerequisites
- Complete the onboarding process.
- A GitHub repository with admin access to set up GitHub Actions.
- Port's GitHub Ocean integration is installed.
Set up data model
First, create a custom blueprint in Port to store the leaked secret information.
-
Go to the Builder page in Port.
-
Click on
+ Blueprint. -
Click on the
{...}button in the top right corner, and chooseEdit JSON. -
Add this JSON schema:
Leaked secret blueprint (Click to expand)
{"identifier": "leaked_secret","description": "Leaked secrets","title": "Leaked Secret","icon": "Key","schema": {"properties": {"commit": {"type": "string","title": "Commit"},"commit_msg": {"type": "string","title": "Commit Message"},"author": {"type": "string","title": "Author"},"files": {"items": {"type": "string"},"type": "array","title": "Files"},"urls": {"icon": "DefaultProperty","type": "array","title": "URLs","items": {"type": "string","format": "url"}},"locations": {"items": {"type": "object"},"type": "array","title": "Locations"}},"required": []},"mirrorProperties": {},"calculationProperties": {},"aggregationProperties": {},"relations": {"service": {"title": "Service","target": "service","required": false,"many": false},"user": {"title": "User","target": "_user","required": false,"many": false}}} -
Click
Saveto create the blueprint.
Configure data source
Configure GitHub Ocean secret scanning
Add the secret-scanning-alerts resource to your GitHub Ocean integration's port-app-config.yml. Ocean uses GitHub's native secret scanning with the state: "open" selector to ingest only open alerts and hideSecret: true to avoid exposing secret content.
GitHub Ocean secret-scanning configuration (Click to expand)
resources:
- kind: secret-scanning-alerts
selector:
query: "true"
state: "open"
hideSecret: true
port:
entity:
mappings:
identifier: .__repository + "/" + (.number | tostring)
title: .number | tostring
blueprint: '"leaked_secret"'
properties:
urls: "[.url]"
relations:
service: .__repository | split("/") | last
The Ocean secret-scanning API provides different fields than Gitleaks (e.g., state, secret_type, url). You may need to extend the leaked_secret blueprint with properties such as state and secret_type to capture all available data from GitHub's native secret scanning.
Set up scanning
The GitHub Ocean integration automatically syncs secret-scanning alerts from GitHub. No GitHub Actions workflow is required. Ensure secret scanning is enabled for your repository.
Let's Test It
To test your integration, you can create a test commit with a fake secret or use the sample data provided below. This section includes a sample webhook response from Gitleaks and the corresponding Port entity that would be created.
Payload
Webhook response data (Click to expand)
{
"body": {
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "gitleaks",
"semanticVersion": "v8.0.0",
"informationUri": "https://github.com/gitleaks",
"rules": [
{
"id": "1password-service-account-token",
"shortDescription": {
"text": "Uncovered a possible 1Password service account token, potentially compromising access to secrets in vaults."
}
},
{
"id": "adafruit-api-key",
"shortDescription": {
"text": "Identified a potential Adafruit API Key, which could lead to unauthorized access to Adafruit services and sensitive data exposure."
}
},
{
"id": "adobe-client-id",
"shortDescription": {
"text": "Detected a pattern that resembles an Adobe OAuth Web Client ID, posing a risk of compromised Adobe integrations and data breaches."
}
},
{
"id": "aws-access-token",
"shortDescription": {
"text": "Identified a pattern that may indicate AWS credentials, risking unauthorized cloud resource access and data breaches on AWS platforms."
}
},
{
"id": "azure-ad-client-secret",
"shortDescription": {
"text": "Azure AD Client Secret"
}
},
{
"id": "beamer-api-token",
"shortDescription": {
"text": "Detected a Beamer API token, potentially compromising content management and exposing sensitive notifications and updates."
}
},
{
"id": "bitbucket-client-id",
"shortDescription": {
"text": "Discovered a potential Bitbucket Client ID, risking unauthorized repository access and potential codebase exposure."
}
},
{
"id": "bitbucket-client-secret",
"shortDescription": {
"text": "Discovered a potential Bitbucket Client Secret, posing a risk of compromised code repositories and unauthorized access."
}
},
{
"id": "bittrex-access-key",
"shortDescription": {
"text": "Identified a Bittrex Access Key, which could lead to unauthorized access to cryptocurrency trading accounts and financial loss."
}
},
{
"id": "bittrex-secret-key",
"shortDescription": {
"text": "Detected a Bittrex Secret Key, potentially compromising cryptocurrency transactions and financial security."
}
},
{
"id": "gitlab-ptt",
"shortDescription": {
"text": "Found a GitLab Pipeline Trigger Token, potentially compromising continuous integration workflows and project security."
}
},
{
"id": "gitlab-rrt",
"shortDescription": {
"text": "Discovered a GitLab Runner Registration Token, posing a risk to CI/CD pipeline integrity and unauthorized access."
}
},
{
"id": "gitlab-runner-authentication-token",
"shortDescription": {
"text": "Discovered a GitLab Runner Authentication Token, posing a risk to CI/CD pipeline integrity and unauthorized access."
}
},
{
"id": "gitlab-runner-authentication-token-routable",
"shortDescription": {
"text": "Discovered a GitLab Runner Authentication Token (Routable), posing a risk to CI/CD pipeline integrity and unauthorized access."
}
},
{
"id": "gitlab-scim-token",
"shortDescription": {
"text": "Discovered a GitLab SCIM Token, posing a risk to unauthorized access for a organization or instance."
}
},
{
"id": "gitlab-session-cookie",
"shortDescription": {
"text": "Discovered a GitLab Session Cookie, posing a risk to unauthorized access to a user account."
}
},
{
"id": "gitter-access-token",
"shortDescription": {
"text": "Uncovered a Gitter Access Token, which may lead to unauthorized access to chat and communication services."
}
},
{
"id": "gocardless-api-token",
"shortDescription": {
"text": "Detected a GoCardless API token, potentially risking unauthorized direct debit payment operations and financial data exposure."
}
},
{
"id": "grafana-api-key",
"shortDescription": {
"text": "Identified a Grafana API key, which could compromise monitoring dashboards and sensitive data analytics."
}
},
{
"id": "grafana-cloud-api-token",
"shortDescription": {
"text": "Found a Grafana cloud API token, risking unauthorized access to cloud-based monitoring services and data exposure."
}
},
{
"id": "grafana-service-account-token",
"shortDescription": {
"text": "Discovered a Grafana service account token, posing a risk of compromised monitoring services and data integrity."
}
},
{
"id": "harness-api-key",
"shortDescription": {
"text": "Identified a Harness Access Token (PAT or SAT), risking unauthorized access to a Harness account."
}
},
{
"id": "hashicorp-tf-api-token",
"shortDescription": {
"text": "Uncovered a HashiCorp Terraform user/org API token, which may lead to unauthorized infrastructure management and security breaches."
}
},
{
"id": "hashicorp-tf-password",
"shortDescription": {
"text": "Identified a HashiCorp Terraform password field, risking unauthorized infrastructure configuration and security breaches."
}
},
{
"id": "heroku-api-key",
"shortDescription": {
"text": "Detected a Heroku API Key, potentially compromising cloud application deployments and operational security."
}
},
{
"id": "hubspot-api-key",
"shortDescription": {
"text": "Found a HubSpot API Token, posing a risk to CRM data integrity and unauthorized marketing operations."
}
},
{
"id": "huggingface-access-token",
"shortDescription": {
"text": "Discovered a Hugging Face Access token, which could lead to unauthorized access to AI models and sensitive data."
}
},
{
"id": "huggingface-organization-api-token",
"shortDescription": {
"text": "Uncovered a Hugging Face Organization API token, potentially compromising AI organization accounts and associated data."
}
},
{
"id": "infracost-api-token",
"shortDescription": {
"text": "Detected an Infracost API Token, risking unauthorized access to cloud cost estimation tools and financial data."
}
},
{
"id": "scalingo-api-token",
"shortDescription": {
"text": "Found a Scalingo API token, posing a risk to cloud platform services and application deployment security."
}
},
{
"id": "sendbird-access-id",
"shortDescription": {
"text": "Discovered a Sendbird Access ID, which could compromise chat and messaging platform integrations."
}
},
{
"id": "sendbird-access-token",
"shortDescription": {
"text": "Uncovered a Sendbird Access Token, potentially risking unauthorized access to communication services and user data."
}
},
{
"id": "sendgrid-api-token",
"shortDescription": {
"text": "Detected a SendGrid API token, posing a risk of unauthorized email service operations and data exposure."
}
},
{
"id": "sendinblue-api-token",
"shortDescription": {
"text": "Identified a Sendinblue API token, which may compromise email marketing services and subscriber data privacy."
}
},
{
"id": "sentry-access-token",
"shortDescription": {
"text": "Found a Sentry.io Access Token (old format), risking unauthorized access to error tracking services and sensitive application data."
}
},
{
"id": "sentry-org-token",
"shortDescription": {
"text": "Found a Sentry.io Organization Token, risking unauthorized access to error tracking services and sensitive application data."
}
},
{
"id": "telegram-bot-api-token",
"shortDescription": {
"text": "Detected a Telegram Bot API Token, risking unauthorized bot operations and message interception on Telegram."
}
},
{
"id": "travisci-access-token",
"shortDescription": {
"text": "Identified a Travis CI Access Token, potentially compromising continuous integration services and codebase security."
}
},
{
"id": "zendesk-secret-key",
"shortDescription": {
"text": "Detected a Zendesk Secret Key, risking unauthorized access to customer support services and sensitive ticketing data."
}
}
]
}
},
"results": [
{
"message": {
"text": "generic-api-key has detected secret for file oops.ts at commit df4331ee30d70b6c93d3a350067ba0560eef7e84."
},
"ruleId": "generic-api-key",
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "oops.ts"
},
"region": {
"startLine": 4,
"startColumn": 8,
"endLine": 4,
"endColumn": 57,
"snippet": {
"text": "REDACTED"
}
}
}
}
],
"partialFingerprints": {
"commitSha": "df4331ee30d70b6c93d3a350067ba0560eef7e84",
"email": "developer@domain.com",
"author": "John Smith",
"date": "2025-07-03T18:36:25Z",
"commitMessage": "update secret for twitter"
},
"properties": {
"tags": []
}
},
{
"message": {
"text": "discord-client-secret has detected secret for file oops.ts at commit df4331ee30d70b6c93d3a350067ba0560eef7e84."
},
"ruleId": "discord-client-secret",
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "oops.ts"
},
"region": {
"startLine": 3,
"startColumn": 8,
"endLine": 3,
"endColumn": 65,
"snippet": {
"text": "REDACTED"
}
}
}
}
],
"partialFingerprints": {
"commitSha": "df4331ee30d70b6c93d3a350067ba0560eef7e84",
"email": "developer@domain.com",
"author": "John Smith",
"date": "2025-07-03T18:36:25Z",
"commitMessage": "update secret for twitter"
},
"properties": {
"tags": []
}
},
{
"message": {
"text": "generic-api-key has detected secret for file src/oops_again.ts at commit df4331ee30d70b6c93d3a350067ba0560eef7e84."
},
"ruleId": "generic-api-key",
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/oops_again.ts"
},
"region": {
"startLine": 4,
"startColumn": 8,
"endLine": 4,
"endColumn": 58,
"snippet": {
"text": "REDACTED"
}
}
}
}
],
"partialFingerprints": {
"commitSha": "df4331ee30d70b6c93d3a350067ba0560eef7e84",
"email": "developer@domain.com",
"author": "John Smith",
"date": "2025-07-03T18:36:25Z",
"commitMessage": "update secret for twitter"
},
"properties": {
"tags": []
}
},
{
"message": {
"text": "slack-webhook-url has detected secret for file src/oops_again.ts at commit df4331ee30d70b6c93d3a350067ba0560eef7e84."
},
"ruleId": "slack-webhook-url",
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "src/oops_again.ts"
},
"region": {
"startLine": 5,
"startColumn": 27,
"endLine": 5,
"endColumn": 103,
"snippet": {
"text": "REDACTED"
}
}
}
}
],
"partialFingerprints": {
"commitSha": "df4331ee30d70b6c93d3a350067ba0560eef7e84",
"email": "developer@domain.com",
"author": "John Smith",
"date": "2025-07-03T18:36:25Z",
"commitMessage": "update secret for twitter"
},
"properties": {
"tags": []
}
}
]
}
]
},
"headers": {
"Host": "ingest.port.io",
"User-Agent": "curl/8.5.0",
"Content-Length": "47867",
"Accept": "*/*",
"Content-Type": "application/json",
"Traceparent": "00-a9dcc35b56eae75b85fc30064d5af241-a52f664817beba5a-01",
"X-Forwarded-Host": "ingest.port.io",
"X-Forwarded-Server": "public-traefik-5649595896-n2gm7",
"X-Real-Ip": "10.0.18.65",
"X-Replaced-Path": "/RP9JvkFCMkxCNigQ",
"Accept-Encoding": "gzip",
"host": "ingest.port.io",
"user-agent": "curl/8.5.0",
"content-length": "47867",
"accept": "*/*",
"content-type": "application/json",
"traceparent": "00-a9dcc35b56eae75b85fc30064d5af241-a52f664817beba5a-01",
"x-forwarded-host": "ingest.port.io",
"x-forwarded-server": "public-traefik-5649595896-n2gm7",
"x-real-ip": "10.0.18.65",
"x-replaced-path": "/RP9JvkFCMkxCNigQ",
"accept-encoding": "gzip"
},
"queryParams": {
"repo": "PeyGis/gitleaks-port-demo"
}
}
Mapping Result
After the webhook is processed, you should see entities created in Port with the following structure:
Leaked secret response entity in Port (Click to expand)
{
"identifier": "slack-webhook-url:444811d775394062236b36f07ea7827959b57913",
"title": "slack-webhook-url has detected secret for file src/oops_again.ts at commit 444811d775394062236b36f07ea7827959b57913.",
"team": [],
"properties": {
"commit": "444811d775394062236b36f07ea7827959b57913",
"commit_msg": "update secret",
"author": "Joe Smith",
"files": [
"src/oops_again.ts"
],
"urls": [
"https://github.com/PeyGis/gitleaks-port-demo/blob/444811d775394062236b36f07ea7827959b57913/src/oops_again.ts#L5"
],
"locations": [
{
"physicalLocation": {
"region": {
"endLine": 5,
"snippet": {
"text": "REDACTED"
},
"endColumn": 103,
"startLine": 5,
"startColumn": 27
},
"artifactLocation": {
"uri": "src/oops_again.ts"
}
}
}
]
},
"relations": {
"service": "gitleaks-port-demo"
},
"icon": "Key"
}