Back to skill

Security audit

Didit Proof Of Address

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it uploads very sensitive address documents to a third party while leaving retention and output exposure insufficiently controlled.

Review privacy and retention requirements before installing. Use this only when users knowingly consent to sending proof-of-address documents and extracted personal data to Didit, avoid running it in logged automation environments, and prefer adding controls to disable request retention and redact output by default.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/verify_address.py:37
Finding
Proof-of-address documents are retained by the third-party service by default## Vulnerability Details **File Location**: `scripts/verify_address.py:37-42` **Related Documentation**: `SKILL.md:85` **Vulnerability Type**: Privacy-sensitive third-party data retention **Risk Level**: Medium The Skill documentation states that the `save_api_request` parameter defaults to `true`: ```text | `save_api_request` | boolean | No | `true` | Save in Business Console | ``` The request code does not override that default: ```python data = {} if vendor_data: data["vendor_data"] = vendor_data r = requests.post(ENDPOINT, headers={"x-api-key": api_key}, files=files, data=data, timeout=60) ``` ### Technical Analysis Proof-of-address documents may contain names, residential addresses, account information, transaction details, customer identifiers, and other personal or financial data. The script submits these documents to Didit without setting `save_api_request` to `false`. According to the included documentation, omission of this parameter causes the request to be saved in the Didit Business Console. Remote submission is necessary for the declared verification functionality, but persistent retention is not demonstrated to be necessary. Accepting retention by default therefore exceeds the minimum data-handling privileges needed to perform a verification request. This is not covert exfiltration: the destination is a fixed HTTPS endpoint belonging to the declared verification provider, and the uploaded document is required for the service. The security concern is avoidable retention after processing. ### Attack Path 1. A user invokes the script with a utility bill, bank statement, government record, or similar proof-of-address document. 2. The script uploads the complete document to `https://verification.didit.me/v3/poa/`. 3. The script omits `save_api_request`, causing the documented default value of `true` to apply. 4. The request and associated document are retained in the th ...[truncated 726 chars]
Remediation
## Remediation Suggestions - Set `save_api_request` to `false` for every request by default: ```python data = {"save_api_request": "false"} if vendor_data: data["vendor_data"] = vendor_data ``` - Add an explicit opt-in option such as `--save-api-request` for workflows that genuinely require console retention. - Before enabling retention, display or document a clear warning describing what is stored, why it is stored, who can access it, and how long it is retained. - Document deletion procedures and the vendor's retention controls. - Apply data-minimization and consent requirements appropriate to proof-of-address documents. - Restrict access to retained requests in the Didit Business Console using least-privilege roles and account security controls.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/verify_address.py:59
Finding
Complete verification responses containing personal data are printed to standard output## Vulnerability Details **File Location**: `scripts/verify_address.py:59-67` **Vulnerability Type**: Sensitive information exposure through process output **Risk Level**: Medium ```python result = verify_address(args.document, args.vendor_data) print(json.dumps(result, indent=2)) poa = result.get("poa", {}) status = poa.get("status", "Unknown") address = poa.get("address", {}) print(f"\n--- Status: {status} ---") if address: ``` ### Technical Analysis The complete API response is serialized and printed to standard output without filtering or redaction. According to `SKILL.md`, a successful response can include: - The subject's name - Raw and formatted residential addresses - Parsed address components - Precise latitude and longitude - A temporary document URL - Verification identifiers and timestamps - Verification warnings and associated metadata Standard output is not inherently a confidential channel. It may be captured by terminal recording, shell redirection, CI/CD logs, agent transcripts, notebook output, process supervisors, centralized logging systems, or automation platforms. Printing all fields by default increases disclosure beyond what is required to communicate a verification status. ### Attack Path 1. A user submits a proof-of-address document. 2. Didit returns a response containing extracted personal information and potentially a temporary document URL. 3. The script executes `print(json.dumps(result, indent=2))`. 4. The execution environment captures or retains standard output. 5. Another user, service operator, log reader, or attacker with access to those records retrieves the exposed information. 6. If the temporary document URL remains valid, the recipient may also be able to access the corresponding document during its validity period. ### Impact Assessment The issue does not grant additional local system privileges. Its scope is unauthorized read access to verification ...[truncated 395 chars]
Remediation
## Remediation Suggestions - Print only the minimum verification result by default, such as the request identifier and approval status. - Remove the unconditional full-response output. - Require an explicit option such as `--json` or `--show-sensitive` before displaying the complete response. - Redact high-risk fields, including `document_file`, names, raw addresses, formatted addresses, geolocation coordinates, and vendor identifiers. - Send operational errors and non-sensitive status information to appropriate output channels without including response bodies that may contain personal data. - Warn users that redirected or captured output may contain sensitive information. - Configure CI, agent, and centralized logging systems to avoid retaining verification responses. - If structured output is required for automation, support writing it to a user-selected file with restrictive permissions rather than printing it unconditionally.

T08 · Insecure Dependencies

Note
Location
SKILL.md:246
Finding
Runtime dependency is installed without version or integrity constraints## Vulnerability Details **File Location**: `SKILL.md:246` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ```bash # Requires: pip install requests ``` ### Technical Analysis The installation instruction retrieves the latest package version selected by the package index and dependency resolver at installation time. It provides no exact version, lock file, hash verification, or isolated-environment guidance. The package name `requests` is consistent with the established Python HTTP library, and the reviewed project does not direct users to an unknown package index or suspicious source. Therefore, no malicious dependency is demonstrated. Nevertheless, unconstrained installation creates a mutable and non-reproducible supply-chain boundary. A future compromised, malicious, or incompatible release—or one of its resolved transitive dependencies—could alter behavior after the Skill has been reviewed. ### Attack Path 1. A user follows the documented `pip install requests` instruction. 2. The package resolver selects whatever package and dependency versions are current and compatible at that time. 3. A compromised or unsafe future release is downloaded because no reviewed version or integrity hash is enforced. 4. Package installation or subsequent import executes the affected dependency code. 5. That code runs with the permissions of the user or automation account performing the installation or invoking the script. ### Impact Assessment If the dependency supply chain were compromised, malicious package code could execute with the same local privileges as the installing or invoking process. This could potentially expose the `DIDIT_API_KEY`, submitted documents, accessible files, and other process environment data, or perform arbitrary network requests. The current evidence does not establish an active malicious package or direct compromise, so the finding is rated Low. Its scope is the r ...[truncated 87 chars]
Remediation
## Remediation Suggestions - Declare a reviewed dependency version or narrowly bounded compatible range in a dependency manifest. - Generate and commit a lock file appropriate to the selected package-management workflow. - Use package hashes where practical, for example through a hash-locked requirements file. - Install dependencies from the expected authenticated package index and avoid untrusted mirrors. - Perform installation in a dedicated virtual environment with no unnecessary privileges. - Periodically update pinned versions after security review and vulnerability scanning. - Document a reproducible installation command based on the locked dependency set instead of an unconstrained `pip install requests`.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Tainted flow: 'api_key' from os.environ.get (line 26, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
data = {}
        if vendor_data:
            data["vendor_data"] = vendor_data
        r = requests.post(ENDPOINT, headers={"x-api-key": api_key},
                          files=files, data=data, timeout=60)
    if r.status_code not in (200, 201):
        print(f"Error {r.status_code}: {r.text}", file=sys.stderr)
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill requires environment access and makes outbound network requests, but it does not declare a restrictive tool scope such as permissions or allowed-tools. That creates unnecessary ambient authority: an agent/runtime may permit broader tool use than intended, making exfiltration or unintended network activity easier if the skill is modified, misused, or composed with other instructions.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This skill sends highly sensitive proof-of-address documents and extracted personal data to a third-party verification provider, yet the description does not clearly warn users that their files and PII will leave the local system. Users may unknowingly transmit utility bills, bank statements, names, addresses, and metadata to an external service, creating privacy, compliance, and consent risks.

External Transmission

Medium
Category
Data Exfiltration
Content
```python
import requests

response = requests.post(
    "https://verification.didit.me/v3/poa/",
    headers={"x-api-key": "YOUR_API_KEY"},
    files={"document": ("utility_bill.pdf", open("bill.pdf", "rb"), "application/pdf")},
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
const formData = new FormData();
formData.append("document", documentFile);

const response = await fetch("https://verification.didit.me/v3/poa/", {
  method: "POST",
  headers: { "x-api-key": "YOUR_API_KEY" },
  body: formData,
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This script uploads highly sensitive proof-of-address documents and optional tracking metadata to a third-party API without an explicit runtime warning, consent check, or clear notice about external transmission. In the skill context, transmitting bank statements, utility bills, and address data to an outside service is expected functionality, but it still creates privacy and compliance risk if users or operators are not adequately informed.

Static analysis

No suspicious patterns detected.