Rust-backed secrets detection plugin for MCP Gateway
Project description
Secrets Detection (Rust)
Rust-backed secrets detection and redaction for ContextForge and MCP Gateway.
Features
- Detects likely credentials in prompt arguments, tool inputs, tool outputs, and resource content
- Built-in detectors for AWS keys, Google API keys, GitHub tokens, Stripe keys, Slack tokens, and private key blocks
- Optional broad detectors for generic API key assignments, JWT-like strings, long hex strings, and base64-like secrets
- Blocking, redaction, or metadata-only reporting modes
- Recursive scanning for nested dicts, lists, tuples, Pydantic-style objects,
__dict__, and__slots__ - Optional dotted field allowlist and denylist controls for structured payload scanning
- Sanitized outward metadata that reports finding types and counts, not original secret values
Build
make install
Runtime Requirements
This plugin depends on cpex>=0.1.0,<0.2 and imports hook models from cpex.framework. The compiled Rust extension is mandatory; there is no Python fallback implementation.
Usage
The plugin scans these hooks:
prompt_pre_fetch: scanspayload.argstool_pre_invoke: scans tool invocation payloads before executiontool_post_invoke: scanspayload.resultresource_post_fetch: scanspayload.content.text
Typical uses:
- block requests that contain likely credentials before they reach tools or prompts
- redact secrets from returned tool or resource payloads
- surface sanitized findings metadata for observability and tuning
Detection Coverage
Enabled by default:
aws_access_key_idaws_secret_access_keygoogle_api_keygithub_tokenstripe_secret_keyslack_tokenprivate_key_block
Disabled by default because they are broader and more false-positive-prone:
generic_api_key_assignmentjwt_likehex_secret_32base64_24
The detectors are regex-based. They do not verify whether a credential is real, active, or revoked.
Configuration
config:
enabled:
aws_access_key_id: true
aws_secret_access_key: true
google_api_key: true
github_token: true
stripe_secret_key: true
slack_token: true
private_key_block: true
generic_api_key_assignment: false
jwt_like: false
hex_secret_32: false
base64_24: false
redact: false
redaction_text: "***REDACTED***"
block_on_detection: true
min_findings_to_block: 1
field_allowlist: []
field_denylist: []
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
dict | built-in defaults | Per-detector enable flags; unspecified detectors inherit defaults |
redact |
bool | false |
Replace matched secret values in returned payloads |
redaction_text |
string | "***REDACTED***" |
Replacement text used when redact=true |
block_on_detection |
bool | true |
Return a violation when enough findings are present |
min_findings_to_block |
integer | 1 |
Minimum finding count required before blocking |
field_allowlist |
list[string] | [] |
Dotted field paths eligible for scanning; empty means all structured fields are eligible |
field_denylist |
list[string] | [] |
Dotted field paths excluded from scanning; denylist entries take precedence over allowlist entries |
Field Filtering
field_allowlist and field_denylist apply to structured scan targets:
prompt_pre_fetch: paths are relative topayload.argstool_pre_invoke: paths are relative topayload.argstool_post_invoke: paths are relative topayload.result
For example, accounts.credentials.token matches payload.args.accounts.credentials.token in pre-hooks and payload.result.accounts.credentials.token in tool_post_invoke.
Rules:
- An empty
field_allowlistscans all structured fields. - A non-empty
field_allowlistscans only the listed paths and their descendants. - A
field_denylistentry excludes that path and all descendants. - When both lists match,
field_denylistwins. - Parent containers are still traversed to reach nested allowlisted paths.
- Matching is segment-aware:
layer1does not matchlayer10. - Lists and tuples are transparent to field matching; numeric indices are not used.
- Mapping keys themselves are not scanned.
- Direct scalar scan targets, including
payload.content.textinresource_post_fetch, retain current behavior and are not filtered by field paths.
Valid field paths use non-empty dot-separated segments. Empty paths, whitespace-only paths, leading or trailing dots, and empty segments such as layer1..token are rejected during plugin initialization.
Example:
config:
field_allowlist:
- "layer1"
- "accounts.credentials"
field_denylist:
- "layer1.layer2.layer3"
- "accounts.credentials.test_token"
Behavior Notes
- Redaction preserves payload shape where possible instead of flattening everything to plain dicts.
aws_secret_access_keyrecognizes=and:assignments with optional single or double quotes around the value.base64_24uses capture-group redaction so leading non-base64 boundary characters are preserved.- Broad detectors remain opt-in to reduce noisy matches on ordinary identifiers.
- Binary resource bodies are not scanned;
resource_post_fetchonly scans text content exposed aspayload.content.text. - The plugin does not decode archives, compressed data, or arbitrary encoded blobs before scanning.
Returned Metadata
prompt_pre_fetch, tool_pre_invoke, tool_post_invoke, and resource_post_fetch accept an optional extensions parameter carrying OpenTelemetry trace context. When a trace context is present (via extensions.request.trace_id), the plugin emits operational metrics on result.metadata["secrets_detection"] with the following schema:
result.metadata["secrets_detection"] = {
"total_detections": 2, # int — total number of findings in this call
"total_masked": 2, # int — number redacted (masking action taken)
"total_blocked": 0, # int — number that caused a block (blocking action taken)
"secret_types": ["aws_access_key_id", "slack_token"], # list[str] — distinct type names, sorted, deduped
}
total_masked and total_blocked are mutually exclusive per call: exactly one of them carries the finding count (the other is 0), depending on whether the redaction branch or the blocking branch executed. If neither redaction nor blocking is configured, both are 0 and only total_detections/secret_types are non-zero (findings-only reporting mode).
Gating: Metrics are only emitted when a valid trace_id is present in the trace context (extensions.request.trace_id). No trace context means no result.metadata write at all, regardless of any config flag — this keeps the untraced path byte-for-byte identical to before metrics existed.
Security Note (S1): The plugin never includes raw secret values in result.metadata, logs, or any other output. Only counts and type-category names (e.g. "aws_access_key_id") are reported.
tool_pre_invoke is in scope for this metrics contract on the same terms as the other 3 hooks: it accepts extensions and emits result.metadata["secrets_detection"] under the identical gating/schema once a valid trace_id is present.
Blocking responses use the SECRETS_DETECTED violation code.
Migration Note
Version 0.3.8 adds optional field filtering:
field_allowlistandfield_denylistdefault to empty lists, so existing configurations keep scanning the same fields as before.- When configured, field filters affect detection counts, metadata, redaction,
min_findings_to_block, and blocking decisions. field_denylistentries take precedence overfield_allowlistentries.
Version 0.3.7 is a breaking change for any existing consumer reading detection metadata:
- The old flat
result.metadatakeys —secrets_redacted,count(redaction path) andsecrets_findings,count(findings-only path) — have been removed entirely. There is no compatibility shim; code reading those keys will silently stop receiving data. - Detection/redaction/blocking metrics are now emitted on
result.metadata["secrets_detection"]instead, with keystotal_detections,total_masked,total_blocked, andsecret_types(see Returned Metadata above for the full schema). - All 4 hooks —
prompt_pre_fetch,tool_pre_invoke,tool_post_invoke, andresource_post_fetch— now accept a new optionalextensionsparameter carrying OpenTelemetry trace context. Emission toresult.metadata["secrets_detection"]is gated solely onextensions.request.trace_idbeing present and valid — if no trace context is supplied, no metrics are written at all, regardless of any config flag. - Consumers that previously read
result.metadata["secrets_redacted"]/result.metadata["secrets_findings"]unconditionally must migrate to readingresult.metadata["secrets_detection"]and must pass atrace_idviaextensionsto receive metrics. tool_pre_invokepreviously never receivedextensionsand could never emit metrics (a regression introduced earlier on this branch, since fixed) — it now follows the exact same contract as the other 3 hooks.
Security Notes
- Outward-facing findings metadata and violation examples do not include original matched secret values.
- Enable broad detectors only after testing against representative payloads.
- The detector is best-effort pattern matching and should complement, not replace, upstream secret management controls.
Testing
make ci
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cpex_secrets_detection-0.3.9.tar.gz.
File metadata
- Download URL: cpex_secrets_detection-0.3.9.tar.gz
- Upload date:
- Size: 57.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb4c7a964f64c2272e4e910a9539c58327fe9cc2e8cee49abbb0b77b8696c6cc
|
|
| MD5 |
99982cfc36642dedccb771c748c639bc
|
|
| BLAKE2b-256 |
db3da99f84176361fc56b23085f89eee1e0b541453de04469db3c17812f29152
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9.tar.gz:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9.tar.gz -
Subject digest:
bb4c7a964f64c2272e4e910a9539c58327fe9cc2e8cee49abbb0b77b8696c6cc - Sigstore transparency entry: 2173067979
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cpex_secrets_detection-0.3.9-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: cpex_secrets_detection-0.3.9-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 776.1 kB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5901b652ff64180c3e63f95cd25fe3a078fa0a4a66b506aa0cd680227a09a5e
|
|
| MD5 |
d6109e83974c8228f535fa9a2c35e2a2
|
|
| BLAKE2b-256 |
223556e54d9adbf85f74c7ca4df5c047b22338e524865b1707c58d68c6a3b1c5
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9-cp311-abi3-win_amd64.whl:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9-cp311-abi3-win_amd64.whl -
Subject digest:
d5901b652ff64180c3e63f95cd25fe3a078fa0a4a66b506aa0cd680227a09a5e - Sigstore transparency entry: 2173068051
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 846.2 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
743f99059742c607616a7937963a07ca33ec132efe879ce4fffdb013141141d0
|
|
| MD5 |
ce45556f0bf46bede98564f194da098f
|
|
| BLAKE2b-256 |
2ff57823633bfea762910df55e8b02ebebe80b1f8e57800a3224c8add339ee7d
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl -
Subject digest:
743f99059742c607616a7937963a07ca33ec132efe879ce4fffdb013141141d0 - Sigstore transparency entry: 2173068018
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl.
File metadata
- Download URL: cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl
- Upload date:
- Size: 883.0 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ s390x
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cacd4b58cc3d4f54555ba73b29788973a6228ccc4ee9c4d4196674c2c59d7579
|
|
| MD5 |
625bb2369f917da7cb7c3504b13aa911
|
|
| BLAKE2b-256 |
ae71c37843fa74616e9ae412f877a4ce2644dfd485ae03e91f1b6906ce8bbb17
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl -
Subject digest:
cacd4b58cc3d4f54555ba73b29788973a6228ccc4ee9c4d4196674c2c59d7579 - Sigstore transparency entry: 2173068009
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl.
File metadata
- Download URL: cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl
- Upload date:
- Size: 873.3 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ ppc64le
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba72dca59851e58c7059ed246d6a18c3191827986d206647c28ffd95789c7aa3
|
|
| MD5 |
6a32a3764541a5772a8e0b78eb65013b
|
|
| BLAKE2b-256 |
29519d2db8854b30f562ad37e106edff7fb15c3f99d54db0ca3faa1e81c49c8e
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl -
Subject digest:
ba72dca59851e58c7059ed246d6a18c3191827986d206647c28ffd95789c7aa3 - Sigstore transparency entry: 2173068042
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl.
File metadata
- Download URL: cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl
- Upload date:
- Size: 790.1 kB
- Tags: CPython 3.11+, manylinux: glibc 2.34+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
885a3071f76a33f068b67767c8b64bb31a90b284626753ba09f1c6d3c03866ff
|
|
| MD5 |
9720a9b88f3978615f03c2d3363b78b6
|
|
| BLAKE2b-256 |
95954635f8f0bfc567cdf78a42a22a81ef07dc3c2be7c575576d493e856a7ed4
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl -
Subject digest:
885a3071f76a33f068b67767c8b64bb31a90b284626753ba09f1c6d3c03866ff - Sigstore transparency entry: 2173067995
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file cpex_secrets_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: cpex_secrets_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 748.5 kB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e910949f4cdbf2ad313d13fb2055643d649c739cc6b86a72171a5a213825c90d
|
|
| MD5 |
da2aef68c666e9e7a48dd08f62f5aeaa
|
|
| BLAKE2b-256 |
623c6c966fe0b0ab170f1140be507358d99869ab45fef3b6f379d5ad65237850
|
Provenance
The following attestation bundles were made for cpex_secrets_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl:
Publisher:
release-rust-python-package.yaml on IBM/cpex-plugins
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cpex_secrets_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
e910949f4cdbf2ad313d13fb2055643d649c739cc6b86a72171a5a213825c90d - Sigstore transparency entry: 2173068027
- Sigstore integration time:
-
Permalink:
IBM/cpex-plugins@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/IBM
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-rust-python-package.yaml@d29d3069645c67c1afe8858600fc5ab4f30e635f -
Trigger Event:
workflow_dispatch
-
Statement type: