Back to skill

Security audit

nearai-verify

Security checks for vulnerabilities and agentic risk

Overview

The skill performs useful privacy checks, but its assurances can exceed what the evidence actually proves.

Use this as a diagnostic aid before trusting it with sensitive prompts. A successful endpoint check does not establish trusted enclave software, and recent-history output does not prove which model completed a response. Review the separate plugin before enabling its credential-backed integration. The 17 bundled regression tests pass, but do not resolve these assurance gaps.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
attest.py
Finding

Hardware attestation is accepted without authenticating the enclave workload

Content
View full analysis

Impact

An attacker-controlled enclave application can satisfy the implemented checks while deliberately logging or exporting data. The resulting ATTESTED result can falsely reassure a user evaluating whether to send sensitive prompts. This verifier does not itself send those prompts, and exploitation is conditional on the attacker meeting the hardware-evidence requirements.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The endpoint classification and fallback-warning functionality matches part of the description, and its configuration, log, network, and cache access support that purpose. However, the description centrally promises cryptographic and message-level verification that the supplied code does not perform. The code explicitly states that nothing is cryptographically verified and that attestation is not yet implemented. Its recent-turn reporting also relies on request-start records rather than proof of completed responses. These are material capability gaps, not merely implementation details.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The supplied code substantially implements the endpoint-attestation portion of the description, but the declaration materially overstates its scope. It neither reads conversation or gateway history nor examines fallback routing, and it explicitly states that endpoint attestation says nothing about individual messages. References to a separate check.py do not implement those capabilities in this chunk. Dependency installation and external attestation-service requests are supporting implementation details, not unrelated capabilities.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Installing the named plugin is a plausible supporting implementation detail and is not itself the mismatch. However, the entire supplied code stops at updating, installing, and restarting; it neither performs nor explicitly invokes the verification and reporting workflow described. The plugin's name alone does not establish that those checks occur.

Content

No source excerpt is available for this finding.

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

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

md
**The fallback chain is the thing to look at.** A chain like
`DeepSeek (TEE) → gpt-oss (TEE) → gpt-5.4-mini (OpenAI)` is fully private until
both NEAR models fail, at which point the same prompt goes to OpenAI with no
warning. If prompts must never leave the enclave, the fix is a chain with no
non-TEE tail — not a note in a doc.

Tainted flow: 'req' from pathlib.Path.read_text (line 397, file read) → urllib.request.urlopen (network output)

High
Category
Data Flow
Confidence
80% confidence
Finding

File contents flow to a network sink. This may indicate data exfiltration of sensitive files.

Content

Scanner excerpt · attest.py (reported line 399)May include surrounding context.

python
try:
        req = urllib.request.Request(NRAS_URL, data=json.dumps(payload).encode(),
                                     headers={"Content-Type": "application/json"})
        body = json.loads(urllib.request.urlopen(req, timeout=90).read())
        claims_b64 = body[0][1].split(".")[1]
        claims_b64 += "=" * ((4 - len(claims_b64) % 4) % 4)
        claims = json.loads(base64.urlsafe_b64decode(claims_b64))

The manifest promises cryptographic endpoint attestation, but this implementation only classifies endpoints from configuration and a public catalog.

High
Category
Excessive Agency
Confidence
99% confidence
Finding

The manifest explicitly promises Intel TDX quote verification and message-level proof through the nearai-verify plugin. This file performs neither operation and explicitly states at L125-L126 that attestation is not implemented, leaving the skill's central cryptographic assurance unsupported by this implementation.

Content

No source excerpt is available for this finding.

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: env, file_read, file_write, network, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

The trigger "prove it" overlaps with ordinary requests unrelated to endpoint verification.

Medium
Category
Trigger Abuse
Confidence
97% confidence
Finding

The skill explicitly activates on "prove it," a common request that can concern any claim, without requiring a preceding discussion of NEAR AI, TEE privacy, or response provenance. This can invoke endpoint verification when the user instead wants evidence for an unrelated answer.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · attest.py (reported line 54)May include surrounding context.

python
def probe(mod: str) -> tuple[bool, str]:
    """Is `mod` importable here, or in our private venv?"""
    try:
        m = __import__(mod)
        return True, f"{getattr(m, '__version__', '?')} (current interpreter)"
    except ImportError:
        pass

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · attest.py (reported line 60)May include surrounding context.

python
pass
    vp = venv_python()
    if vp:
        r = subprocess.run([str(vp), "-c", f"import {mod},sys;print(getattr({mod},'__version__','?'))"],
                           capture_output=True, text=True)
        if r.returncode == 0:
            return True, f"{r.stdout.strip()} (skill venv)"

Tainted flow: 'vp' from os.environ.get (line 58, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · attest.py (reported line 60)May include surrounding context.

python
pass
    vp = venv_python()
    if vp:
        r = subprocess.run([str(vp), "-c", f"import {mod},sys;print(getattr({mod},'__version__','?'))"],
                           capture_output=True, text=True)
        if r.returncode == 0:
            return True, f"{r.stdout.strip()} (skill venv)"

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · attest.py (reported line 114)May include surrounding context.

python
def cmd_install() -> int:
    print(f"Creating venv at {VENV}")
    VENV.parent.mkdir(parents=True, exist_ok=True)
    r = subprocess.run([sys.executable, "-m", "venv", str(VENV)])
    if r.returncode:
        print("  venv creation failed - is python3-venv installed?")
        return 1

Tainted flow: 'VENV' from os.environ.get (line 35, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · attest.py (reported line 114)May include surrounding context.

python
def cmd_install() -> int:
    print(f"Creating venv at {VENV}")
    VENV.parent.mkdir(parents=True, exist_ok=True)
    r = subprocess.run([sys.executable, "-m", "venv", str(VENV)])
    if r.returncode:
        print("  venv creation failed - is python3-venv installed?")
        return 1

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · attest.py (reported line 119)May include surrounding context.

python
print("  venv creation failed - is python3-venv installed?")
        return 1
    print(f"Installing {' '.join(EXTRAS)}")
    r = subprocess.run([str(VENV / "bin" / "pip"), "install", "-q", *EXTRAS])
    if r.returncode:
        print("  install failed - see pip output above")
        return 1

Tainted flow: 'VENV' from os.environ.get (line 35, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · attest.py (reported line 119)May include surrounding context.

python
print("  venv creation failed - is python3-venv installed?")
        return 1
    print(f"Installing {' '.join(EXTRAS)}")
    r = subprocess.run([str(VENV / "bin" / "pip"), "install", "-q", *EXTRAS])
    if r.returncode:
        print("  install failed - see pip output above")
        return 1

The manifest promises plugin-backed message-level proof, but the implementation explicitly reports that this capability is unavailable.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The manifest says the skill uses the nearai-verify OpenClaw plugin for message-level proof, including requests to verify the latest response. However, L158–L161 report that this proof level is unavailable and that the required provider plugin is 'not built yet'; L491 further confirms that endpoint attestation proves nothing about an individual message. Consequently, the implemented endpoint checks cannot fulfill the advertised response-verification capability.

Content

No source excerpt is available for this finding.

The documented 'actually served' history counts request-start events rather than evidence of completed responses.

Medium
Category
Excessive Agency
Confidence
98% confidence
Finding

The history parser treats request-start log entries as proof that a model actually served a turn, without checking completion, failure, or correlation to the returned response. Failed attempts, retries, and fallbacks can therefore produce incorrect model attribution and privacy summaries; this is particularly consequential for a skill used to decide whether sensitive data remains inside a TEE, although the CLAIMED label limits the assurance presented.

Content

No source excerpt is available for this finding.