Back to skill

Security audit

Didit Kyc Onboarding

Security checks for vulnerabilities and agentic risk

Overview

This KYC skill is mostly coherent, but it handles highly sensitive identity data and exposes too much of it by default, so it needs careful review before installation.

Install only if you are prepared to treat all outputs as regulated KYC data. Avoid running the default CLI against real users until full-response printing is removed or redacted, use opaque vendor IDs, restrict logs and transcripts, confirm consent and retention rules, and require explicit operator approval for billing, manual status changes, reports, AML/NFC/contact checks, and blocklisting.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run_kyc.py:174
Finding
Sensitive KYC Records and Verification Session Credentials Exposed Through Standard Output## Vulnerability Details **File Location**: `scripts/run_kyc.py`, lines 174-188 **Vulnerability Type**: Sensitive data exposure through console output and downstream logging **Risk Level**: High ### Vulnerable Code ```python elif args.command == "session": result = create_kyc_session(args.workflow_id, args.vendor_data, args.callback, args.language) print(json.dumps(result, indent=2)) print(f"\n--- Session Created ---") print(f"Session ID: {result.get('session_id')}") print(f"Verification URL: {result.get('url')}") print(f"\nSend the URL to your user to start verification.") elif args.command == "decision": if args.poll: print(f"Polling session {args.session_id} every {args.interval}s...") result = poll_decision(args.session_id, args.interval, args.max_wait) else: result = get_decision(args.session_id) print(json.dumps(result, indent=2)) ``` The documented decision structure in `SKILL.md`, lines 207-225, demonstrates that the serialized response may contain highly sensitive fields: ```json { "session_id": "...", "status": "Approved", "features": ["ID_VERIFICATION", "LIVENESS", "FACE_MATCH"], "id_verifications": [{ "status": "Approved", "document_type": "PASSPORT", "issuing_country": "USA", "first_name": "John", "last_name": "Doe", "date_of_birth": "1990-01-15", "document_number": "ABC123456", "expiry_date": "2030-06-01", "gender": "M", "nationality": "USA", "mrz": "P<USADOE<<JOHN<<<<<<<<<<<..." }], "liveness_checks": [{ "status": "Approved", "method": "PASSIVE", "score": 92.5 }], "face_matches": [{ "status": "Approved", "score": 97.3 }], "aml_screenings": [], "warnings": [] } ``` ### Technical Analysis The `session` and `decision` c ...[truncated 2282 chars]
Remediation
## Remediation Suggestions 1. Remove full-response serialization from the default `session` and `decision` command paths. 2. Print only the minimum required fields, such as a redacted session identifier and decision status. 3. Redact at least: - `session_token` - Verification URLs or URL tokens - Names and dates of birth - Document and personal identification numbers - MRZ data - Biometric and liveness details 4. If complete output is operationally necessary, require an explicit option such as `--show-sensitive`, display a prominent warning, and disable that option in non-interactive or production environments by default. 5. Provide a secure output-file option that creates files with restrictive permissions rather than routing sensitive records through stdout. 6. Document secure retention, access-control, deletion, and audit requirements for any exported KYC records. 7. Add automated tests confirming that default command output never contains session tokens, document numbers, MRZ fields, dates of birth, or biometric data.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:353
Finding
Unpinned Third-Party Dependency Installation## Vulnerability Details **File Location**: `SKILL.md`, lines 353-356 **Vulnerability Type**: Uncontrolled third-party dependency resolution **Risk Level**: Medium ### Vulnerable Code ```bash # Requires: pip install requests export DIDIT_API_KEY="your_api_key" ``` ### Technical Analysis The installation guidance instructs users to install `requests` without a pinned version, integrity hash, lock file, or explicit trusted package index. The code is therefore executed with whichever version the user's current pip configuration resolves at installation time. Although `requests` is a legitimate package, the reviewed Skill does not constrain the retrieved artifact. A compromised upstream release, malicious package-index mirror, altered pip configuration, or future incompatible version could change the effective code executed by the Skill after this audit. This weakens reproducibility and transfers supply-chain trust to the invoking environment without validation. ### Attack Path 1. A user follows the documented `pip install requests` instruction. 2. pip resolves the dependency using the user's configured package indexes and current package metadata. 3. A compromised index, malicious mirror, compromised release, or uncontrolled future version supplies an unsafe artifact. 4. The package is installed into the user's Python environment. 5. Installation behavior or imported package code executes with the privileges of the user running the Skill. 6. Malicious code could access the process environment, including `DIDIT_API_KEY`, and any data available to the KYC process. ### Impact Assessment Successful supply-chain compromise would execute code with the privileges of the user or service account installing or running the Skill. Potentially accessible assets include the Didit API key, KYC API responses, local files available to that account, and network resources reachable from the execution environment. The Skill does not ...[truncated 183 chars]
Remediation
## Remediation Suggestions 1. Add a dependency manifest containing a specifically reviewed `requests` version. 2. Record cryptographic hashes for all direct and transitive distributions. 3. Install with hash verification, for example: ```bash python -m pip install --require-hashes -r requirements.txt ``` 4. Generate and commit a lock file using a dependency-locking tool appropriate to the project. 5. Document the expected trusted Python package index and prevent fallback to untrusted or dependency-confusion-prone indexes. 6. Run dependency vulnerability and provenance checks in CI. 7. Periodically update the pinned dependency through a controlled review process rather than resolving arbitrary latest versions during deployment.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (13)

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill requires environment access and performs network operations, but the manifest does not declare a corresponding tool scope such as permissions or allowed-tools. This creates a transparency and least-privilege problem: an agent or reviewer may not realize the skill can exfiltrate data to external services or consume secrets from the environment.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill describes collecting and returning highly sensitive identity data, including names, date of birth, document numbers, and biometric verification results, without any privacy, retention, consent, or handling warning. In a KYC workflow this is especially risky because the data is regulated, high-value for identity theft, and likely subject to strict legal controls.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The documented behavior expands beyond KYC session handling into account registration, email OTP verification, billing inspection, and credit top-up. That mismatch can mislead users about the operational and financial consequences of invoking the skill, increasing the chance of unintended account creation or paid actions.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The onboarding instructions tell users to programmatically register an account and top up billing without clearly warning that these steps create persistent accounts and can lead to charges. This is dangerous because users may treat the skill as a simple verification demo while unintentionally performing account lifecycle and payment actions.

External Transmission

Medium
Category
Data Exfiltration
Content
BASE = "https://verification.didit.me/v3"

# 1. Create a KYC workflow (one-time setup — reuse the workflow_id for all users)
workflow = requests.post(f"{BASE}/workflows/", headers=headers, json={
    "workflow_label": "KYC Onboarding",
    "workflow_type": "kyc",
    "is_liveness_enabled": True,
Confidence
92% confidence
Finding
This code sends workflow configuration and authentication headers to an external third-party service. External transmission is expected for a KYC integration, but because the skill lacks prominent data-handling disclosures and explicit scope declarations, it still represents a real security/privacy concern rather than a false positive.

External Transmission

Medium
Category
Data Exfiltration
Content
workflow_id = workflow["uuid"]

# 2. Create a session for a specific user
session = requests.post(f"{BASE}/session/", headers=headers, json={
    "workflow_id": workflow_id,
    "vendor_data": "user-abc-123",
    "callback": "https://yourapp.com/verification-done",
Confidence
97% confidence
Finding
This request creates a KYC session and transmits user-linked data such as vendor identifiers and callback information to an external service, and the overall workflow later processes identity and biometric information. In the KYC context, third-party transmission of user onboarding data is highly sensitive and should be explicitly disclosed and tightly controlled.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The skill includes capabilities to manually alter verification outcomes, request resubmissions, blocklist users, and generate reports, which are materially broader and more sensitive than simply creating a session and retrieving a decision. In the KYC context, these actions affect user access, fraud controls, and handling of sensitive identity records, so under-disclosure increases misuse risk.

External Transmission

Medium
Category
Data Exfiltration
Content
### Block Fraudulent Users

```python
requests.post(f"{BASE}/blocklist/add/",
    headers=headers,
    json={"session_id": session_id, "blocklist_face": True, "blocklist_document": True})
```
Confidence
88% confidence
Finding
This code transmits a session identifier to a third-party endpoint to add a person or document to a blocklist, which is a sensitive enforcement action with downstream consequences for users. While part of the service API, it is more dangerous than ordinary data transfer because it can permanently affect future onboarding outcomes and is under-disclosed in the skill description.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The optional variants extend the flow into AML screening, phone/email verification, and NFC reading, which materially broaden both data collection and regulatory scope beyond the stated ID-and-selfie onboarding flow. Users may invoke the skill without realizing it can trigger additional screening or process extra categories of personal data.

External Transmission

Medium
Category
Data Exfiltration
Content
Add sanctions/PEP screening to catch high-risk individuals:

```python
requests.post(f"{BASE}/workflows/", headers=headers, json={
    "workflow_type": "kyc",
    "is_liveness_enabled": True,
    "is_face_match_enabled": True,
Confidence
89% confidence
Finding
This request enables AML screening through an external provider, expanding third-party processing into sanctions/PEP checks and potentially additional regulated data handling. In a KYC skill, that broadening of screening scope is sensitive and should not be implicit or under-documented.

External Transmission

Medium
Category
Data Exfiltration
Content
Add contact verification to the flow:

```python
requests.post(f"{BASE}/workflows/", headers=headers, json={
    "workflow_type": "kyc",
    "is_liveness_enabled": True,
    "is_face_match_enabled": True,
Confidence
86% confidence
Finding
This external request enables phone and email verification, causing additional categories of personal data to be transmitted and processed beyond the baseline KYC flow. The risk is not that network use exists, but that the skill broadens data collection without matching disclosure or scope constraints.

External Transmission

Medium
Category
Data Exfiltration
Content
For passports with NFC chips — highest assurance:

```python
requests.post(f"{BASE}/workflows/", headers=headers, json={
    "workflow_type": "kyc",
    "is_liveness_enabled": True,
    "is_face_match_enabled": True,
Confidence
85% confidence
Finding
This request enables NFC-based passport chip reading, which increases the sensitivity of the external processing by involving higher-assurance document data. In identity verification contexts, this is a meaningful expansion of capability and data handling that warrants explicit disclosure and tighter controls.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The sample session creation request sets `"language": "en"`, which forces a specific language for the verification flow. Under the language/locale policy, skills should not impose a language without user opt-in unless the restriction is clearly documented and justified.