Back to skill

Security audit

Self zkID verification

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent Self identity integration guide, but its examples under-warn about sensitive identity data and include an unsafe smart-contract verification pattern developers could copy.

Review before installing or copying the examples. Use the skill only with explicit privacy notices, minimal requested disclosures, careful retention rules, pinned dependency versions, and contract code that cryptographically binds any verified address to the proof subject or another trusted identity signal. Do not put raw identity fields on-chain unless you intentionally accept public permanent exposure.

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
references/contracts.md:29
Finding

Untrusted user data can assign verification status to an arbitrary address

Content
View full analysis

Vulnerability Details

File Location: references/contracts.md, lines 29–35
Vulnerability Type: Authorization bypass through untrusted identity binding
Risk Level: High

solidity
function customVerificationHook(
    bytes memory output,
    bytes memory userData
) internal override {
    address user = abi.decode(userData, (address));
    verified[user] = true;
}

Technical Analysis

The verification callback ignores the verified proof output and derives the account receiving verification status exclusively from userData. According to the documented flow, the user supplies the corresponding context data when submitting a proof.

The example does not validate that the decoded address is cryptographically bound to the proof subject, an authenticated caller, or a trusted public signal. Consequently, possession of a valid proof may be sufficient to mark an unrelated address as verified.

Attack Path

  1. An attacker obtains or generates a valid identity proof.
  2. The attacker encodes a target address in the user-controlled context data.
  3. The attacker submits the valid proof together with the encoded target address.
  4. Hub V2 validates the proof and invokes the verification callback.
  5. customVerificationHook decodes the attacker-selected address without checking its relationship to the proof.
  6. The contract executes verified[target] = true, granting verification status to the selected account.

Impact Assessment

An attacker with one valid proof could potentially confer verified status on an arbitrary account. If downstream logic relies on verified[address] for KYC enforcement, token gating, airdrop eligibility, governance, or restricted access, an account that has not independently completed identity verification could receive those privileges.

The precise scope depends on how the mapping is used by the integrating contract and associated applications.

Remediation
View remediation

Remediation Suggestions

  • Bind the credited address to a proof-authenticated public signal or another value cryptographically covered by the proof.
  • If verification is intended for the transaction initiator, use a trusted caller identity and ensure the callback architecture preserves and validates that binding.
  • Explicitly compare the decoded address with the authenticated proof subject before modifying state.
  • Reject zero addresses, malformed context data, and any identity mismatch.
  • Track and consume scope-bound nullifiers where one-time or Sybil-resistant verification is required.
  • Avoid using untrusted context data as an authorization principal unless it has been authenticated.
  • Add negative tests demonstrating that a valid proof cannot verify an arbitrary third-party address or reuse a nullifier to grant benefits repeatedly.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:17
Finding

Third-party dependency installation instructions use mutable, unpinned versions

Content
View full analysis

Vulnerability Details

File Locations: SKILL.md:17, references/backend.md:4, references/frontend.md:4, and references/contracts.md:151
Vulnerability Type: Unpinned third-party dependencies
Risk Level: Medium

SKILL.md, line 17:

bash
npm install @selfxyz/qrcode @selfxyz/core

references/backend.md, line 4:

bash
npm install @selfxyz/core

references/frontend.md, line 4:

bash
npm install @selfxyz/qrcode

references/contracts.md, line 151:

bash
forge install selfxyz/self

Technical Analysis

The installation commands do not select exact npm package versions, immutable repository commits, or verified release tags. As a result, users following the instructions at different times may retrieve code that differs from the code available when the Skill was reviewed.

Although SKILL.md states a minimum version requirement for @selfxyz/core, a minimum version does not provide reproducibility or prevent a later incompatible or compromised release from being selected. The Foundry command similarly refers to a mutable repository source without an immutable commit reference.

Attack Path

  1. A referenced package, release, maintainer account, or upstream repository is compromised, or a future release introduces malicious behavior.
  2. A user follows one of the documented installation commands.
  3. The package manager resolves the current mutable version or repository revision.
  4. The changed dependency enters the application or smart-contract build.
  5. Malicious or vulnerable dependency behavior may execute during installation, compilation, testing, deployment, or application runtime.

Impact Assessment

The resulting privileges depend on the dependency and execution stage. A compromised npm dependency could potentially operate with the permissions of the developer or CI process, access environment secrets available to that process, modify build ...[truncated 333 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin npm packages to exact reviewed versions rather than relying on latest-version resolution or broad ranges.
  • Commit and enforce a package lockfile containing registry integrity metadata.
  • Use reproducible CI installation commands such as npm ci.
  • Pin the Foundry dependency to an immutable, reviewed commit hash or a trusted fixed release tag.
  • Enable automated dependency and provenance review before accepting upgrades.
  • Review package lifecycle scripts and restrict or disable them where operationally possible.
  • Document a controlled upgrade procedure that includes source review, security testing, and lockfile updates.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (8)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill instructs developers to send identity-proof material to a backend endpoint and even return derived identity attributes such as nationality, but it does not include any user-facing notice, consent guidance, or data-minimization warning. In a privacy-sensitive identity/KYC context, this omission can lead integrators to build flows where users are unaware that sensitive identity-related verification artifacts or derived attributes are transmitted to and processed by the application server.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The example backend code reads and returns disclosed identity attributes such as nationality and potentially other PII from the verification result without any warning about data minimization, retention, or downstream handling. In a privacy-preserving identity integration guide, this can lead implementers to unnecessarily collect, log, or expose sensitive attributes, undermining the privacy guarantees users may expect from zero-knowledge verification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The local development instructions recommend exposing the verification endpoint through ngrok without cautioning that the endpoint will become publicly reachable and may receive untrusted traffic. Implementers may copy this pattern into insecure environments, exposing verification routes, test infrastructure, or sensitive request payloads without authentication, rate limiting, or environment separation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation encourages decoding and using highly sensitive identity attributes such as name, nationality, date of birth, gender, expiry date, and ID number directly in a Solidity contract without any warning that on-chain storage and calldata are public and permanent. In the context of a privacy-preserving identity protocol, this is especially risky because developers may inadvertently deanonymize users or create immutable on-chain PII exposure that conflicts with the protocol’s privacy goals.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/backend.md (reported line 18)May include surrounding context.

md
const selfApp = new SelfAppBuilder({
  appName: "My App",                         // display name in Self app
  scope: "my-app-scope",                     // unique scope string
  endpoint: "https://api.example.com/verify", // backend URL or contract address
  endpointType: "https",                     // "https" | "https-staging" | "celo" | "celo-staging"
  userId: "0xabc...",                        // user identifier
  userIdType: "hex",                         // "hex" | "uuid"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/frontend.md (reported line 17)May include surrounding context.

md
const selfApp = new SelfAppBuilder({
  appName: "My App",                         // display name in Self app
  scope: "my-app-scope",                     // unique scope string
  endpoint: "https://api.example.com/verify", // backend URL or contract address
  endpointType: "https",                     // "https" | "https-staging" | "celo" | "celo-staging"
  userId: "0xabc...",                        // user identifier
  userIdType: "hex",                         // "hex" | "uuid"

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/frontend.md (reported line 69)May include surrounding context.

md
const selfApp = new SelfAppBuilder({
  appName: "My App",                         // display name in Self app
  scope: "my-app-scope",                     // unique scope string
  endpoint: "https://api.example.com/verify", // backend URL or contract address
  endpointType: "https",                     // "https" | "https-staging" | "celo" | "celo-staging"
  userId: "0xabc...",                        // user identifier
  userIdType: "hex",                         // "hex" | "uuid"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The example requests a broad set of highly sensitive identity attributes, including full name, date of birth, ID number, issuing state, and sanctions status, without any accompanying guidance on data minimization, consent, retention, or secure handling. In a privacy-focused identity integration skill, this is dangerous because developers may copy the example verbatim and over-collect regulated personal data far beyond what is necessary for the use case.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.