Back to skill

Security audit

sluice

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly behaves like a local secret scanner, but its advertised private-key redaction is incomplete and can leave key material in outbound text.

Install only if you understand that this is a lightweight local scanner, not a complete DLP control. Do not rely on its redact mode for private-key blocks until that detector is fixed to remove the full key block; use scan as a warning gate and manually inspect high-severity findings. Avoid running bench.py on systems where /home/workloft contains private drafts unless that local corpus access is intended.

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

Error
Location
sluice/detectors.py:110
Finding

Incomplete Private-Key Block Redaction Exposes Key Material

Content
View full analysis

Vulnerability Details

File Location: sluice/detectors.py:110-116
Vulnerability Type: Incomplete sensitive-data redaction
Risk Level: High

Vulnerable Code

python
Detector(
    "private_key_block", "high",
    re.compile(
        r"-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----"
    ),
    "private-key-block",
),

Redaction in sluice/core.py:104-112 replaces only the span returned by this detector:

python
out = []
cursor = 0
for f in findings:
    out.append(text[cursor:f.start])
    out.append(template.format(label=f.label))
    cursor = f.end
out.append(text[cursor:])
return "".join(out)

Technical Analysis

The private-key detector matches only the opening marker, such as:

text
-----BEGIN OPENSSH PRIVATE KEY-----

It does not include the encoded key body or the corresponding closing marker in the finding span. Because redact() replaces exactly the matched span, output can retain nearly all sensitive key material:

text
[redacted:private-key-block]
<encoded private-key body>
-----END OPENSSH PRIVATE KEY-----

Removing the opening marker does not cryptographically invalidate or protect the underlying key material. An observer can restore the standard header or otherwise parse the retained encoded data.

The existing detector test confirms only that the opening marker is detected. It does not verify that the complete key body is removed during redaction.

Attack Path

  1. An outbound draft or generated message contains a PEM, OpenSSH, or supported private-key block.
  2. An agent invokes sluice redact as recommended before sending or publishing the content.
  3. The detector reports a high-severity finding whose span covers only the opening marker.
  4. The redaction routine replaces that marker but preserves the key body and closing marker.
  5. The downstream publishing, email, chat, or queueing command send ...[truncated 860 chars]
Remediation
View remediation

Remediation Suggestions

  • Change the detector to match the complete private-key block, from the opening marker through the corresponding closing marker, including multiline key data.
  • Ensure the opening and closing key types correspond rather than accepting unrelated terminators.
  • Bound the multiline match to prevent excessive scanning and define explicit handling for malformed or unterminated blocks.
  • Consider redacting from a recognized opening marker to the matching closing marker; for an unterminated block, conservatively redact through the end of the input.
  • Add tests covering complete RSA, EC, DSA, OpenSSH, PGP, and generic private-key blocks.
  • Add assertions that redacted output contains neither the encoded body nor either key marker.
  • Add malformed and unterminated-block tests to prevent partial disclosure regressions.
  • Retain the high severity and default blocking behavior for scan mode. Avoid treating detection of only a header as sufficient evidence that redaction is safe.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented behavior claims a pure standard-library outbound guard that blocks or redacts secrets before release, but the analyzed behavior indicates local filesystem scanning under specific home-directory paths, benchmarking logic unrelated to outbound protection, lack of actual blocking/redaction, and dependence on an external module. This mismatch is dangerous because operators may trust the skill as a protective control while it silently performs broader data access and fails to provide the promised egress protection.

Content

No source excerpt is available for this finding.

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 · bench.py (reported line 42)May include surrounding context.

python
return [
        ("anthropic_key", f"export ANTHROPIC_API_KEY=sk-ant-api03-{_rand(80)}"),
        ("openrouter_key", f"OPENROUTER_KEY=sk-or-v1-{''.join(_secrets.choice(hexs) for _ in range(64))}"),
        ("openai_key", f"the key sk-{_rand(48)} goes in .env"),
        ("gitlab_pat", f"GITLAB_TOKEN=glpat-{_rand(20)} for the mirror push"),
        ("github_pat", f"use ghp_{_rand(36)} to open the PR"),
        ("aws_access_key", f"aws creds: AKIA{_rand(16, string.ascii_uppercase + string.digits)}"),

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill advertises a security-sensitive function but declares no explicit tool scope or permissions boundaries, despite requiring environment and file-read capabilities. In an agent setting, that omission weakens least-privilege guarantees and can allow broader-than-expected access to secrets or local data during execution.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The benchmark enumerates and reads hard-coded local content from /home/workloft/workloft-site and /home/workloft/drafts, which goes beyond a narrowly scoped outbound-message guard and touches unrelated local data. Even though this file only benchmarks scanning and does not exfiltrate content, it creates an unnecessary capability to inspect private drafts and published material on the host machine, increasing privacy and data-exposure risk if run in the wrong environment.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The docstring presents the published articles and drafts as clean enough that any medium/high finding is a false alarm. But later output logic explicitly warns that flagged files may be legitimate content in security articles, showing the corpus is not reliably 'clean by construction' and that such findings are not necessarily false positives.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
bench.py:40