Back to skill

Security audit

Bridge

Security checks for vulnerabilities and agentic risk

Overview

This skill looks like a local prototype for human-task tracking, but it overstates escrow and proof-verification guarantees in a way that could mislead users handling money or sensitive real-world evidence.

Treat this as a local demo only. Do not use it for real payments, escrow, worker assignment, or sensitive physical-world tasks unless authentication, authorization, durable storage, real payment custody, strong proof attestation, privacy controls, and pinned dependencies are added.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (5)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
bridge/app.py:51
Finding

Unauthenticated Access Allows Arbitrary Task Disclosure and State Mutation

Content
View full analysis
TaskResponse: """Request human actuation — create a task with escrow.""" task = create_task( description=request.description, budget_usdc=request.budget_usdc, location=request.location, verification_criteria=request.verification_criteria, priority=request.priority, deadline_hours=request.deadline_hours, ) return _task_to_response(task) @app.get("/v1/tasks", response_model=TaskListResponse) async def list_all(status: str | None = Query(default=None)) -> TaskListResponse: """List all tasks, optionally filtered by status.""" tasks = list_tasks(status) return TaskListResponse( tasks=[_task_to_response(t) for t in tasks], total=len(tasks), ) @app.get("/v1/tasks/{task_id}", response_model=TaskResponse) async def get_by_id(task_id: str) -> TaskResponse: """Get a task by ID.""" task = get_task(task_id) if task is None: raise HTTPException(status_code=404, detail=f"Task not found: {task_id}") return _task_to_response(task) @app.post("/v1/tasks/{task_id}/verify", response_model=VerifyResponse) async def verify(task_id: str, request: VerifyRequest) -> VerifyResponse: """Submit proof and verify against criteria.""" task = get_task(task_id) if task is None: raise HTTPException(status_code=404, detail=f"Task not found: {task_id}") if task.status == "disputed": raise HTTPException(status_code=409, detail="Task is disputed — cannot verify") update_task_status(task_id, "proof_submitted", worker_id=request.worker_id) all_passed, results = verify_all(task.verification_criteria, request.proofs) if all_passed ...[truncated 2384 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
bridge/models.py:39
Finding

Tasks Without Verification Criteria Pass Automatically

Content
View full analysis
tuple[bool, list[CriterionResult]]: """Verify all criteria against submitted proofs. Returns (all_passed, results). """ proof_by_type = {p.type: p for p in proofs} results: list[CriterionResult] = [] for criterion in criteria: proof = proof_by_type.get(criterion.type) if proof is None: results.append(CriterionResult( type=criterion.type, passed=False, detail=f"No proof submitted for {criterion.type}", )) continue verifier = _VERIFIERS.get(criterion.type) if verifier is None: results.append(CriterionResult( type=criterion.type, passed=False, detail=f"Unknown proof type: {criterion.type}", )) continue results.append(verifier(criterion, proof)) all_passed = all(r.passed for r in results) return all_passed, results ``` ```python if all_passed: update_task_status(task_id, "completed", escrow_status="released") escrow_action = "release" else: update_task_status(task_id, "failed", escrow_status="locked") escrow_action = "hold" ``` ### Technical Analysis The creation model pe ...[truncated 1424 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
bridge/verifier.py:23
Finding

Client-Controlled Evidence Can Forge Every Supported Proof Type

Content
View full analysis
CriterionResult: """Verify worker was at the required location.""" params = criterion.params proof_data = proof.data required_lat = float(params.get("latitude", 0)) required_lon = float(params.get("longitude", 0)) radius_m = float(params.get("radius_m", 100)) submitted_lat = float(proof_data.get("latitude", 0)) submitted_lon = float(proof_data.get("longitude", 0)) distance = _haversine(required_lat, required_lon, submitted_lat, submitted_lon) passed = distance <= radius_m return CriterionResult( type="gps_proof", passed=passed, detail=f"Distance: {distance:.0f}m (max: {radius_m:.0f}m)", ) def verify_photo_proof(criterion: VerificationCriterion, proof: ProofItem) -> CriterionResult: """Verify required number of photos submitted with unique hashes.""" min_photos = int(criterion.params.get("min_photos", 1)) hashes = proof.data.get("photo_hashes", []) unique_hashes = set(hashes) passed = len(unique_hashes) >= min_photos return CriterionResult( type="photo_proof", passed=passed, detail=f"Photos: {len(unique_hashes)} unique (min: {min_photos})", ) def verify_timestamp_proof(criterion: VerificationCriterion, proof: ProofItem) -> CriterionResult: """Verify task completed within time limit.""" max_hours = float(criterion.params.get("max_hours", 24)) accepted = proof.data.get("accepted_at", "") completed = proof.data.get("completed_at", "") if not accepted or not completed: return CriterionResult(type="timestamp_proof", passed=False, detail="Missing timestamps") # Simple hour calculation from ISO st ...[truncated 3158 chars]
Remediation
View remediation
= accepted_at`. - Compare against the task’s authoritative deadline, not only caller-provided fields. 5. For signatures: - Define a canonical payload containing the task ID, worker ID, proof digest, timestamp, and one-time nonce. - Verify the signature cryptographically against the authorized worker’s registered public key. - Reject replayed nonces and unsupported algorithms. 6. Use discriminated, strongly typed Pydantic models for criterion parameters and proof data rather than unrestricted `dict[str, Any]`. 7. Add adversarial tests covering copied coordinates, arbitrary hash strings, reversed timestamps, replayed evidence, and malformed signatures. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:4
Finding

Runtime Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation

other

Error
Location
SKILL.md:38
Finding

Documented Escrow and Automatic Refund Guarantees Are Not Implemented

Content
View full analysis
BridgeTask | None: task = _tasks.get(task_id) if task is None: return None task.status = status if escrow_status: task.escrow_status = escrow_status if worker_id: task.worker_id = worker_id return task ``` ### Technical Analysis The implementation contains no wallet, payment processor, smart contract, ledger transaction, custody operation, balance validation, or settlement confirmation. “Locked,” “released,” “frozen,” and “refunded” are only string values on objects held in the process-local `_tasks` dictionary. The code also contains no scheduler or request-time expiration logic that compares `created_at` and `deadline_hours`. Therefore, the ...[truncated 1400 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill markets itself as an escrow and verification platform with formal proof checks and release-by-invariants, but the documented behavior indicates those guarantees may not actually exist. In an escrow context, this mismatch is dangerous because users or agents may rely on the claimed safety properties when transferring funds, sensitive evidence, or assigning physical-world tasks, leading to fraud, unauthorized release, or unsafe task execution.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

update_task_status allows arbitrary transitions of both status and escrow_status without enforcing any business rules, verification-criteria checks, or allowed state machine transitions. In an escrow platform, this means a caller elsewhere in the system could mark funds as released or refunded before proof verification or dispute resolution, directly undermining the core escrow-by-invariants security model described by the skill.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The behavior does not match the platform's stated security model of formal proof verification: the 'signature_proof' criterion is effectively presence-only, not authenticity verification. In the context of Bridge's escrow-by-invariants model, this weakens a core control and could allow fraudulent submissions to pass a required verification gate, leading to disputes, false attestations, or unauthorized fund release.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This is a real vulnerability because the function claims to verify a cryptographic signature but actually accepts any non-empty string. In an escrow and proof-verification system, that lets an attacker satisfy a supposedly strong authenticity requirement with arbitrary data, undermining trust in task completion and potentially triggering improper payment release.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This markdown file says 'Request human help for physical-world tasks,' which is a very broad invocation description and does not define specific trigger phrases, scope boundaries, or negative examples. That ambiguity could cause the skill to match many ordinary requests involving errands or real-world help.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation instructs users to collect and submit GPS coordinates, photos, and timestamps without warning that these are sensitive forms of personal and location data. In this skill's context, omission of privacy and consent warnings increases the risk of oversharing, unsafe collection of third-party data, and mishandling of evidence tied to real-world identities and places.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 20)May include surrounding context.

Create a task with verification criteria

bash
curl -s -X POST http://localhost:8015/v1/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Pick up package at 123 Main St, photograph it",

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

This endpoint submits proof artifacts such as GPS data and photo hashes, which are sensitive verification data tied to physical-world activity. In the absence of documented authentication, authorization, encryption, retention limits, or privacy controls, transmitting such evidence creates a meaningful risk of unauthorized access, tampering, or privacy harm.

Content

Scanner excerpt · SKILL.md (reported line 37)May include surrounding context.

Submit proof and verify

bash
curl -s -X POST http://localhost:8015/v1/tasks/TASK_ID/verify \
  -H "Content-Type: application/json" \
  -d '{
    "worker_id": "worker-1",

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 53)May include surrounding context.

Dispute a task

bash
curl -s -X POST http://localhost:8015/v1/tasks/TASK_ID/dispute \
  -H "Content-Type: application/json" \
  -d '{"reason": "GPS proof appears faked"}' | jq

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
90% confidence
Finding

The skill claims autonomous escrow decisions based on verification outcomes, yet the surrounding findings indicate little or no real proof validation. Automated release, freeze, or refund decisions in a financial and physical-task context are dangerous when decision criteria are weak, unverifiable, or purely declarative, because they can enable fraud or wrongful denial/release of funds at scale.

Content

Scanner excerpt · SKILL.md (reported line 58)May include surrounding context.

-d '{"reason": "GPS proof appears faked"}' | jq

text

Freezes escrow. No verification possible while disputed.

## Other endpoints

Static analysis

No suspicious patterns detected.