Encoded Exfiltration Detection (Rust)
High-performance encoded exfiltration detection for ContextForge and MCP Gateway.
Features
- Detects suspicious encoded payloads in prompt args, tool outputs, and resource content
- Scans common exfil encodings:
- base64
- base64url
- hex
- percent-encoding
- escaped hex
- Scores candidates using decoded length, entropy, printable ratio, sensitive keywords, and egress hints
- Optional redaction instead of hard blocking
- Recursive scanning of nested dicts, lists, and JSON-like string payloads
- Allowlist regex support for known-safe encoded strings
- Decode-depth and recursion-depth guardrails
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_fetchtool_post_invokeresource_post_fetch
Typical uses:
- block suspicious encoded payloads before they leave the gateway
- redact encoded secrets or staged exfil fragments from tool results
- surface findings metadata for review and tuning
Detection Model
Each candidate encoded segment is decoded and scored. The detector looks for combinations of:
- sufficient decoded length
- suspicious entropy
- printable decoded content
- sensitive markers such as
password,secret,token,authorization, orprivate key - egress hints such as
curl,wget,webhook,upload,socket, orpastebin
The plugin can also inspect JSON strings recursively so encoded content nested inside serialized blobs is still visible to the detector.
Configuration
Important settings include:
enabled: per-encoding enable flagsmin_encoded_lengthmin_decoded_lengthmin_entropymin_printable_ratiomin_suspicion_scoremax_scan_string_lengthmax_findings_per_valueredactredaction_textblock_on_detectionmin_findings_to_blockallowlist_patternsextra_sensitive_keywordsextra_egress_hintsmax_decode_depthmax_recursion_depthparse_json_strings
Returned Metadata
prompt_pre_fetch, 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) and at least one detection occurred, the plugin emits operational metrics on result.metadata["encoded_exfil_detection"] with the following schema:
result.metadata["encoded_exfil_detection"] = {
"total_detections": 2, # int — total number of findings in this call
"encoding_types": ["base64", "hex"], # list[str] — distinct encoding names, sorted, deduped
"redacted": True, # bool — present only when the redact branch fired
}
redacted is only included when redact=true is configured and the payload was actually rewritten in this call; it is omitted otherwise (its absence means "not redacted this call", not "false").
Gating: Metrics are only emitted when a valid trace_id is present in the trace context (extensions.request.trace_id) and the scan produced at least one detection. No trace context, or a clean payload, means no result.metadata write at all, regardless of any config flag — this keeps the untraced/clean path byte-for-byte identical to before metrics existed.
Security Note (S1): The plugin never includes raw finding content, matched/decoded payload text, or per-finding path/score detail in result.metadata. Only the total count and the distinct encoding names are reported.
Blocking responses use the ENCODED_EXFIL_DETECTED violation code.
Migration Note
Version 0.3.6 is a breaking change for any existing consumer reading detection metadata:
- The old flat
result.metadatakeys —encoded_exfil_count,encoded_exfil_findings,encoded_exfil_redacted, andimplementation— have been removed entirely. There is no compatibility shim; code reading those keys will silently stop receiving data. (These keys were already dropped at the gateway before this change, since the gateway's metadata sanitizer treats each top-levelresult.metadatakey as a plugin namespace expecting a dict value, andencoded_exfil_count/implementationare scalars — so this migration removes a write that was already dead-on-arrival downstream.) - Detection metrics are now emitted on
result.metadata["encoded_exfil_detection"]instead, with keystotal_detections,encoding_types, and (conditionally)redacted— see Returned Metadata above for the full schema. prompt_pre_fetch,tool_post_invoke, andresource_post_fetchnow accept a new optionalextensionsparameter carrying OpenTelemetry trace context. Emission toresult.metadata["encoded_exfil_detection"]is gated onextensions.request.trace_idbeing present and valid, and requires at least one detection — if no trace context is supplied, or the payload is clean, no metrics are written at all, regardless of any config flag.- Consumers that previously read
result.metadata["encoded_exfil_count"]/result.metadata["encoded_exfil_findings"]/result.metadata["encoded_exfil_redacted"]unconditionally must migrate to readingresult.metadata["encoded_exfil_detection"]and must pass atrace_idviaextensionsto receive metrics. - The
include_detection_detailsconfig flag no longer has any influence overresult.metadata(it never leaks per-finding detail into metrics regardless of its value); it continues to affect only theexamplesfield ofPluginViolation.detailson the blocking path, which is unaffected by this migration.
Security Notes
- Guardrails reject Rust-incompatible allowlist regexes at engine initialization time (during plugin construction). Features such as lookaround and backreferences are not supported.
- Scan and recursion caps exist to keep detection bounded on large payloads.
- Detailed findings can be reduced or sanitized before metadata emission depending on configuration.
Testing
make ci
Metadata
Release files for cpex-encoded-exfil-detection 0.3.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cpex_encoded_exfil_detection-0.3.9.tar.gz | 42.5 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| cpex_encoded_exfil_detection-0.3.9-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ x86-64 | Details |
| cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ IBM System/390x | Details |
| cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ PowerPC 64-le | Details |
| cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ ARM64 | Details |
| cpex_encoded_exfil_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 4.9 MB
Release files / cpex_encoded_exfil_detection-0.3.9.tar.gz
| Download URL | cpex_encoded_exfil_detection-0.3.9.tar.gz |
|---|---|
| Size | 42.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
96193360e7f554c7575abc07e3acfb426c4bca93c8cb764e6d8e4d99b0c4e885
|
|
BLAKE2b-256 checksum How to use checksums |
6ca0b239348efc1ac718d9ce62175af72c5e9ba425e024690fe238ca67d076c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cpex_encoded_exfil_detection-0.3.9-cp311-abi3-win_amd64.whl
| Download URL | cpex_encoded_exfil_detection-0.3.9-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 758.4 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
b48730a8d6c0ec3210938ee1db801b0245dd578c857ddf607e4a9fe72bd2dcb2
|
|
BLAKE2b-256 checksum How to use checksums |
b3adb327ffae96f4e11d125fbee84a9c378cec939e0e7cb10cac5b2eb5f62a69
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl
| Download URL | cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 840.1 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
9cb720c5f5895b722aeadbb656f9255e72d92146de365e62d856b0af9f2756c2
|
|
BLAKE2b-256 checksum How to use checksums |
71cc854b7f85916df477eaa4a1ca7ac1687ddf3f52589e776fe801ddb1c0e11b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl
| Download URL | cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_s390x.whl |
|---|---|
| Size | 881.6 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ IBM System/390x abi3 |
|
SHA-256 checksum How to use checksums |
f77e259e9e43b74fa7bfc2754a743365ceb59a110c6f0b2edb4120daac0c9526
|
|
BLAKE2b-256 checksum How to use checksums |
013fb7ef1c8e41990e976fc4d1e894f85ae0d8b0d0f98ec46f2cf4bd611e208b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl
| Download URL | cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_ppc64le.whl |
|---|---|
| Size | 868.9 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ PowerPC 64-le abi3 |
|
SHA-256 checksum How to use checksums |
ea4d2df967e04fa67d3811edcf32d0430ac7627780c0cdbc991fb5f66f93d4b4
|
|
BLAKE2b-256 checksum How to use checksums |
0ba970468810ec7b0a2773673de6fd347def3fdec1823cb729217733c24b643a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl
| Download URL | cpex_encoded_exfil_detection-0.3.9-cp311-abi3-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 788.2 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
f1e8fcb5a2be2582fb7b87910fbc4ec85624e7157ed0b4169804bc2b6e115b61
|
|
BLAKE2b-256 checksum How to use checksums |
88186174f30a0b7da6a4a83ad1b8cfc4ce07b180f0d2a043e639322a7e1f1395
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / cpex_encoded_exfil_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | cpex_encoded_exfil_detection-0.3.9-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 733.6 kB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c1f20394eee1167c86fbe00de90b2069302822bc4472211e5dcc9b5f8d477191
|
|
BLAKE2b-256 checksum How to use checksums |
fd238f414852060ae1d439e45c330b6bf9051b4dab9074ce1e8c9ff04c6f4777
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency log