Back to skill

Security audit

Security Audit (Sona)

Security checks for vulnerabilities and agentic risk

Overview

This security-audit skill is mostly purpose-aligned, but one wrapper can run an unreviewed hard-coded external audit script and the advertised fail-closed behavior is not reliably enforced.

Review before installing. Prefer invoking artifact/scripts/run_audit_json.sh directly from the skill directory, not scripts/security_audit.sh, until the wrapper is fixed to call the packaged runner. Run it in a read-only, network-denied sandbox against an explicit target path, and do not rely only on shell exit status from the wrapper; parse the JSON .ok field and scanner error state.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (4)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/security_audit.sh:13
Finding

Hard-Coded External Audit Runner Enables Tool Hijacking

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run_audit_json.sh:44
Finding

Scanner Errors Are Silently Converted into Zero Findings

Content
View full analysis
"$TRUFFLE_OUT" 2>/dev/null || true # Semgrep JSON (quiet) semgrep scan --config auto --json --quiet "$TARGET" >"$SEMGREP_OUT" 2>/dev/null || true # Count findings TRUFFLE_COUNT=$(jq -s 'length' "$TRUFFLE_OUT" 2>/dev/null || echo 0) SEMGREP_COUNT=$(jq '.results | length' "$SEMGREP_OUT" 2>/dev/null || echo 0) ``` ### Technical Analysis The script discards the exit status of both TruffleHog and Semgrep through `|| true`. It then suppresses parsing errors and substitutes a finding count of zero when scanner output is absent or invalid. This behavior is fail-open: - A scanner crash is treated like a scan with no findings. - A permission or filesystem error can become zero findings. - A Semgrep rule-download or configuration failure can become zero findings. - Truncated or malformed JSON can become zero findings. - Scanner stderr, which would explain the failure, is discarded. This directly contradicts the Skill’s declared fail-closed security model. The final result can be marked successful when neither third-party scanner completed a valid scan, provided the custom hostile scanner passes. ### Attack Path 1. An attacker supplies a repository or execution environment that causes TruffleHog or Semgrep to terminate unsuccessfully. 2. Possible triggers include unreadable files, malformed scanner configuration, resource exhaustion, missing remote Semgrep rules, or scanner-specific input failures. 3. `|| true` suppresses the nonzero scanner exit status. 4. The resulting output file is empty, partial, or invalid JSON. 5. The `jq` expression fails, and `|| echo 0` converts the failure into a count of zero. 6. If `hostile_audit.py` reports success and the other count is ...[truncated 515 chars]
Remediation
View remediation
"$TRUFFLE_OUT" 2>"$TMPDIR/trufflehog.err" || TRUFFLE_RC=$? SEMGREP_RC=0 semgrep scan --config ./rules/semgrep.yml --json --quiet "$TARGET" \ >"$SEMGREP_OUT" 2>"$TMPDIR/semgrep.err" || SEMGREP_RC=$? if [[ "$TRUFFLE_RC" -ne 0 ]] || ! jq -e . "$TRUFFLE_OUT" >/dev/null; then OK=false fi if [[ "$SEMGREP_RC" -ne 0 ]] || ! jq -e '.results | type == "array"' "$SEMGREP_OUT" >/dev/null; then OK=false fi ``` - Add regression tests for empty output, malformed JSON, scanner crashes, permission failures, and unavailable Semgrep configuration. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_audit_json.sh:48
Finding

Semgrep Auto Configuration Conflicts with the No-Network Permission Declaration

Content
View full analysis
"$SEMGREP_OUT" 2>/dev/null || true ``` The manifest declares: ```json "network": { "required": false, "domains": [] } ``` It also states: ```json "notes": [ "This manifest is required by strict/zero-trust workflows.", "The skill itself does not need network access; scanners may attempt update checks, which should be disabled." ] ``` ### Technical Analysis Semgrep’s `--config auto` selects externally managed rules and may require access to the Semgrep registry. This conflicts with the manifest declaration that network access is not required and no domains are allowed. The audited code does not explicitly transmit repository files and contains no direct exfiltration implementation. Nevertheless, the effective runtime behavior may initiate network communication to retrieve scanning rules. It also makes the security policy dependent on mutable remote content rather than a locally reviewed, version-pinned ruleset. In a network-denied environment, remote configuration retrieval may fail. Because scanner errors are independently suppressed by the runner, this permission mismatch can also contribute to a false-success audit. ### Attack Path 1. A user runs the Skill based on its declaration that no network access is required. 2. Semgrep starts with `--config auto`. 3. Semgrep attempts to resolve or retrieve externally managed rules, or uses remote configuration behavior associated with the installed version. 4. In an unrestricted environment, unexpected outbound traffic occurs and mutable remote rules influence the audit. 5. In a restricted environment, retrieval may fail. 6. The runner suppresses that failure and may interpret the missing or invalid output as zero Semgrep ...[truncated 467 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:4
Finding

Unpinned pip and pipx Installation Executes Mutable Third-Party Dependencies

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The declared behavior and the described audit guarantees do not fully match the actual enforced behavior, including hard-fail manifest requirements and fingerprinting that are not clearly disclosed. In a security tool, this mismatch is dangerous because operators may rely on advertised scans and decision criteria that are absent, incomplete, or materially different, leading to false assurance or unintended denial of use in zero-trust workflows.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run_audit_json.sh <path>

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run_audit_json.sh <path>

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run_audit_json.sh <path>

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run_audit_json.sh <path>

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run_audit_json.sh <path>

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run_audit_json.sh <path>

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This wrapper advertises fail-closed security auditing but unconditionally exits 0, even when the underlying audit script reports findings or operational failure. In automation, CI, or agent execution flows that rely on process exit status to block unsafe installs or enablement, this converts a security gate into a best-effort report and can allow vulnerable or malicious skills to pass unchecked.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/hostile_audit.py (reported line 54)May include surrounding context.

python
PERSISTENCE_GLOBS = [
    "**/*.service",
    "**/*.timer",
    "**/*.plist",
    "**/crontab",
    "**/cron.*",
    "**/systemd/**",

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comments claim the script preserves signal via exit code, but the implementation always exits 0, which is misleading and dangerous for maintainers and integrators. This discrepancy increases the chance that downstream code assumes the shell status is meaningful and silently ignores audit findings or execution errors.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This code performs full-file SHA-256 hashing across the audited repository, which is a substantive read/analysis operation over user data. While the module docstring says it outputs JSON and includes a fingerprint section, there is no explicit runtime disclosure, prompt, or comment near the behavior warning users that complete file contents will be processed for hashing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The script accesses OPENCLAW_AUDIT_LEVEL from the environment, which falls under sensitive environment access checks for this audit rubric. Although this particular variable is not a credential, the code does not provide any nearby disclosure or comment at the access site explaining that environment configuration will influence behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.