Back to skill

Security audit

Veritier - AI Fact-Checking

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated Veritier API purpose, but one included JavaScript test can redirect a bearer API key to an environment-controlled endpoint despite claims that the destination is hardcoded.

Review before installing or running the examples. Use a test key for integration tests, do not run javascript/quickstart/test_integration.mjs with a production key when API_URL can be influenced, and pin dependencies for production use. Expect text, document content, URLs, and private references you submit to be sent to Veritier's hosted API.

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

Warning
Location
javascript/quickstart/test_integration.mjs:14
Finding

Bearer Credential Can Be Redirected to an Arbitrary API Endpoint

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
python/requirements.txt:1
Finding

Python Dependencies Are Unbounded and Installed Without Integrity Pinning

Content
View full analysis
=0.27 python-dotenv>=1.0 flask>=3.0 mcp>=1.0 anyio>=4.0 ``` ### Technical Analysis Every Python dependency uses an open-ended minimum-version constraint. A fresh installation can therefore select any later version accepted by the package resolver. The file also provides no hashes for the expected distributions. This creates two supply-chain weaknesses: - The reviewed source does not determine the code that will actually be installed in the future. - Package integrity is delegated entirely to the configured package index and current resolver state. The affected packages execute in security-sensitive contexts. In particular: - `python-dotenv` loads environment values containing API credentials. - `httpx` handles authenticated outbound requests. - `mcp` and `anyio` participate in the agent-facing MCP proxy. - `flask` exposes the webhook receiver. No evidence in the audited repository shows that any named dependency is currently malicious. The confirmed weakness is non-reproducible, non-integrity-pinned dependency resolution, which increases exposure to compromised future releases, accidental breaking releases, or package-index substitution. ### Attack Path 1. A dependency publisher account, package distribution channel, configured package mirror, or accepted future release is compromised. 2. A malicious package version is published with a version satisfying the broad `>=` requirement. 3. A developer, CI worker, or deployment environment runs: ```bash pip install -r python/requirements.txt ``` 4. The resolver selects and installs the malicious or otherwise unsafe version because there is no upper bound, exact pin, or required hash. 5. Installation-time behavior or imported runtime code executes with the ...[truncated 1070 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (125)

Tainted flow: 'API_KEY' from os.getenv (line 36, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/quickstart/attest_action.py (reported line 59)May include surrounding context.

python
print(f'Attesting action_id="{payload["action_id"]}"\n')

response = httpx.post(
    f"{API_URL}/v1/attest_action",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 24, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/quickstart/extract_text.py (reported line 42)May include surrounding context.

python
print(f"📝 Input text:\n   \"{sample_text}\"\n")
print("⏳ Extracting claims...\n")

response = httpx.post(
    f"{API_URL}/v1/extract",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'cred_id' from os.getenv (line 27, credential/environment) → httpx.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/quickstart/reconstruct_credential.py (reported line 40)May include surrounding context.

python
kids = [k.get("kid") for k in jwk.json().get("keys", [])]
print(f"JWKS kids: {kids}\n")

pub = httpx.get(f"{API_URL}/v1/credentials/{cred_id}", timeout=15.0)
if pub.status_code != 200:
    print(f"GET error ({pub.status_code}): {pub.text}")
    sys.exit(1)

Tainted flow: 'cred_id' from os.getenv (line 27, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/quickstart/reconstruct_credential.py (reported line 65)May include surrounding context.

python
if not API_KEY:
        print("\n--revoke requires VERITIER_API_KEY (same account that issued it).")
        sys.exit(1)
    revoked = httpx.post(
        f"{API_URL}/v1/credentials/{cred_id}/revoke",
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=15.0,

Tainted flow: 'API_KEY' from os.getenv (line 26, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/quickstart/validate_document.py (reported line 44)May include surrounding context.

python
print("Running authenticity scan...\n")

response = httpx.post(
    f"{API_URL}/v1/validate",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 23, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/quickstart/verify_text.py (reported line 41)May include surrounding context.

python
print(f"📝 Input text:\n   \"{sample_text}\"\n")
print("⏳ Verifying claims against live web evidence...\n")

response = httpx.post(
    f"{API_URL}/v1/verify",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'headers' from os.getenv (line 42, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/batch_verify.py (reported line 53)May include surrounding context.

python
print(f"── [{i}/{len(texts)}] ──────────────────────────────────────")
    print(f"📝 \"{text}\"")

    response = httpx.post(
        f"{API_URL}/v1/verify",
        headers=headers,
        json={"text": text, "grounding_mode": "web"},

Tainted flow: 'headers' from os.getenv (line 42, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/batch_verify.py (reported line 67)May include surrounding context.

python
print(f"── [{i}/{len(texts)}] ──────────────────────────────────────")
    print(f"📝 \"{text}\"")

    response = httpx.post(
        f"{API_URL}/v1/verify",
        headers=headers,
        json={"text": text, "grounding_mode": "web"},

Tainted flow: 'API_KEY' from os.getenv (line 29, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/disinformation_shield.py (reported line 50)May include surrounding context.

python
print(f"\n📥 Incoming content:\n   \"{incoming_content}\"\n")
print("⏳ Screening for false claims...\n")

response = httpx.post(
    f"{API_URL}/v1/verify",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 24, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/gate_tool_call.py (reported line 41)May include surrounding context.

python
if API_KEY.startswith("vt_test_"):
    payload["mock_decision"] = "allow"

response = httpx.post(
    f"{API_URL}/v1/attest_action",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 25, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/hallucination_audit.py (reported line 45)May include surrounding context.

python
print(f"   \"{llm_output}\"\n")
print("⏳ Auditing for hallucinations...\n")

response = httpx.post(
    f"{API_URL}/v1/verify",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 21, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/informational_credential.py (reported line 37)May include surrounding context.

python
body["mock_verdict"] = True
    print("TEST MODE: mock_verdict=true plus action_id\n")

response = httpx.post(
    f"{API_URL}/v1/verify",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 26, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/private_references.py (reported line 56)May include surrounding context.

python
print(f"\n📝 Claims to verify:\n   \"{text_to_verify}\"\n")
print("⏳ Verifying against private reference...\n")

response = httpx.post(
    f"{API_URL}/v1/verify",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Tainted flow: 'API_KEY' from os.getenv (line 21, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · python/use-cases/verify_article_url.py (reported line 39)May include surrounding context.

python
print(f"🔗 URL: {url}\n")
print("⏳ Fetching document and verifying claims...\n")

response = httpx.post(
    f"{API_URL}/v1/verify",
    headers={
        "Authorization": f"Bearer {API_KEY}",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 215)May include surrounding context.

  1. Set VERITIER_API_KEY in your environment:
    bash
    # Copy the template
    cp .env.example .env
    # Add your key
    
  2. Run any example:

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a broad trust-gating and attestation system for agent actions, including verification against systems of record, blocking behavior, signed credentials, and claim/document verification services over MCP. The supplied code chunk instead demonstrates only one narrow feature: extracting falsifiable claims from text via a direct call to https://api.veritier.ai/v1/extract. The script explicitly states it extracts claims WITHOUT verifying them, and there is no gating, enforcement, signing, corpus lookup, MCP handling, or document scanning. While claim extraction is mentioned in the declared description, the actual code's primary behavior is much narrower and lacks the core trust-gate functionality, so the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The declared description presents a broad agent trust-gate service that evaluates proposed tool actions against external records/policy sources and blocks unsubstantiated actions, with additional document claim extraction and scanning features. The provided code does something much narrower: it reconstructs an already-issued credential by ID, lists JWKS kids, prints credential fields, and optionally calls a revoke endpoint. While this loosely relates to the description's mention of reconstructable and revocable Ed25519-signed workpapers, the code does not perform the core advertised attestation/gating workflow, does not query the listed systems of record, and does not expose MCP behavior. The revoke action is also an operational capability absent from the declared purpose summary. Therefore the code chunk materially underdelivers and differs in primary purpose from the declaration.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description centers on gating agent tool calls via evidence-backed action attestation against specific systems of record, with signed claim credentials and MCP connectivity. The supplied code does something much narrower and different: it is a quickstart client for submitting document text to a remote validation API and printing the response. While the description mentions document scanning as an additional capability, this code does not implement the primary trust-gate/attestation behavior, does not query the named registries or legal/policy sources, and does not create or verify signed workpapers. This is a material purpose and capability mismatch, not just an implementation detail.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The declared description centers on an agent trust gate: attest_action should check actions against specific systems of record or policy, block calls when records are absent, and produce reconstructable/revocable signed claim credentials. The supplied code instead demonstrates only text claim verification by posting sample text to a remote /v1/verify endpoint with grounding_mode='web'. It prints returned verification results and mentions action_id/attest_action only in comments as optional related functionality, but does not implement that behavior. This is a material mismatch in primary purpose and capabilities, not just an incomplete example, because the actual executed behavior is informational claim verification over direct HTTP rather than a gating mechanism for tool calls.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a security/control-plane capability: gating agent tool calls based on evidence from specific record systems, with signed workpapers and MCP-based connectivity. The supplied code instead is an example batch client script for verifying factual text claims by calling Veritier's hosted API with grounding_mode='web'. It processes a fixed list of claims, handles rate limiting and quota responses, and prints verification results. While there is slight thematic overlap in 'verifying claims,' the core behavior, interfaces, resources accessed, and purpose are materially different from the declared trust-gate functionality.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description centers on an agent trust gate that mediates tool calls based on evidence from specific systems of record and emits signed claim credentials/workpapers. The provided code does something materially different: it is a simple disinformation-screening demo for user-generated text. It posts one text block to a verification endpoint and prints claim-level verdicts and a publishing recommendation. While both involve claim verification at a high level, the core purpose, integration model, resources accessed, and security/attestation features described are absent from the code. This is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description centers on an agent trust gate that evaluates intended tool actions against authoritative records/policies and blocks execution unless evidence exists, with signed credentials and MCP-based connectivity. The supplied code does something materially different: it is a simple demonstration script for post hoc hallucination auditing of generated text. It takes a fixed sample paragraph, calls a single remote verification endpoint at api.veritier.ai with grounding_mode='web', and reports claim verdicts. There is no tool-call interception, no action attestation, no blocking/gating logic, no use of the listed systems of record, no credential signing, and no MCP transport. While the description mentions claim verification, that is only a small overlapping concept; the actual primary behavior is substantially narrower and different.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a security/control skill whose main purpose is to gate agent tool calls using evidence from systems of record and produce signed, revocable workpapers. The supplied code instead is a simple client example for verifying claims against user-provided private references via a remote API. While there is slight overlap with the 'extracts and verifies claims' portion, the primary purpose and key capabilities do not match: there is no action attestation, no enforcement/blocking, no signed credentials, no MCP transport, and no multi-source record lookup. This is a material description-versus-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description centers on an agent control mechanism: gating tool calls, checking proposed actions against authoritative records/policy corpora, and issuing reconstructable signed workpapers. The supplied code instead is a simple command-line use-case script for verifying claims in a public URL via Veritier's hosted API. While the description mentions claim extraction/verification, that is only one secondary piece of the declared functionality; the code lacks the core gate/attestation/signing/MCP behaviors and instead performs document fact-checking over a direct API call. This is a material description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a substantive trust-gate service that evaluates proposed actions against authoritative records, blocks unsupported actions, and issues signed workpapers. The supplied code does not perform those functions. Instead, it is an example webhook receiver for Veritier events: it verifies X-Veritier-Signature with HMAC-SHA256, handles idempotency keys, parses webhook JSON, prints event details, and returns simple status responses. While the payloads may relate to attestation or verification results, this code is only a receiver/consumer of those results, not the system that performs the attestation, evidence lookup, gating, or credential signing. This is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
javascript/quickstart/reconstruct_credential.mjs:16

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
javascript/quickstart/test_integration.mjs:14

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
javascript/mcp/mcp_test.mjs:15

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
javascript/quickstart/extract_text.mjs:12

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
javascript/quickstart/verify_text.mjs:12

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
python/quickstart/attest_action.py:24