T09 · Insecure Skill Coding Practices
- Location
scripts/kb_daily.sh:7- Finding
Arbitrary Shell Command Execution Through Executable .env Loading
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This appears to be a genuine local knowledge-base tool, but it has unsafe review-worthy behavior around command execution from configuration, broad network fetching, and file writes outside intended paths.
Install only if you are comfortable reviewing and running local scripts. Use it with a dedicated KB directory, avoid untrusted .env files, avoid ingesting attacker-supplied URLs or repositories, and do not use file-back targets from untrusted input until the .env loading, URL validation, size limits, and target-concept path handling are fixed.
scripts/kb_daily.sh:7Arbitrary Shell Command Execution Through Executable .env Loading
scripts/kb_ingest.py:95Server-Side Request Forgery Through Unrestricted URL Ingestion
scripts/kb_ask.py:224Arbitrary File Write Through Unsanitized Target Concept Name
scripts/kb_ingest.py:242Detected Prompt-Injection Content Remains in Downstream Agent-Facing Artifacts
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
See: <https://docs.astral.sh/uv/getting-started/installation/>
### 3.2 Configure .env (Optional)
From this repo root:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
See: <https://docs.astral.sh/uv/getting-started/installation/>
### 3.2 Configure .env (Optional)
From this repo root:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
From this repo root:
cp .env.example .env
# then edit .env for your local paths
Referenced artifact was not completely inspected
python3 scripts/kb_ingest.py --root /path/to/kb --source "https://example.com/article"
Referenced artifact was not completely inspected
python3 scripts/kb_ingest.py --root /path/to/kb --source "https://example.com/article"
Referenced artifact was not completely inspected
python3 scripts/kb_ingest.py --root /path/to/kb --source "https://example.com/article"
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
Use `scripts/kb_lint.py`.
## Output rules
Prefer these output forms:
The script automatically sources a .env file from the skill root into the current shell, which executes arbitrary shell syntax rather than merely loading key/value pairs. If an attacker can modify that file, running the wrapper will execute attacker-controlled commands with the user's privileges and expose any exported secrets to downstream subprocesses.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
if [[ -f "$SKILL_ROOT/.env" ]]; then
set -a
# shellcheck disable=SC1090
source "$SKILL_ROOT/.env"
This finding is part of the same unsafe .env loading flow: the skill exports variables from a local .env into the process environment after sourcing it, increasing the blast radius of any malicious content and making credentials available to invoked Python scripts. In a knowledge-base skill that processes local files and repositories, this is more dangerous because the tool is expected to run routinely against user-controlled workspace content.
if [[ -f "$SKILL_ROOT/.env" ]]; then
set -a
# shellcheck disable=SC1090
source "$SKILL_ROOT/.env"
set +a
fi
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env() -> None:
env_path = SKILL_ROOT / ".env"
for k, v in _parse_env_file(env_path).items():
os.environ.setdefault(k, v)
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.
lower = segment.lower()
if score >= 5:
reasons.append("noise")
if re.search(r"ignore previous instructions|system prompt|developer message|tool call|jailbreak", lower):
reasons.append("prompt-like")
if re.search(r"order of the unicorn|unicorn magic|cryptic scar|destiny", lower):
reasons.append("fantasy/anomalous")
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
d": True}
def detect_suspicious_segments(cleaned_markdown: str):
segments = split_segments(cleaned_markdown)
flagged = []
for segment in segments:
if len(flagged) >= MAX_SEGMENTS:
break
reasons = []
score = segment_noise_score(segment)
lower = segment.lower()
if score >= 5:
reasons.append("noise")
if re.search(r"ignore previous instructions|system prompt|developer message|tool call|jailbreak", lower):
reasons.append("prompt-like")
if re.search(r"order of the unicorn|unicorn magic|cryptic scar|destiny", lower):
reasons.append("fantasy/anomalous")
if link_density(segment) > 0.12:
reasons.append("link-heavy")
if reasons:
flagged.append({
"text": segment[:500],
"severity": "MEDIUM" if "prompt-like" in reasons else "LOW",
"action": "warn",
"reasons": reasons,
}
The skill clearly instructs use of filesystem, shell, and network-capable scripts, but it does not declare any explicit tool scope or permission boundaries. That creates an over-privileged operational model where an agent may perform writes, downloads, cloning, and local command execution without clear authorization constraints or user visibility.
The activation criteria are very broad: the skill can trigger for collecting sources, building notes, asking questions, exporting outputs, and health checks across many content types. Over-broad invocation boundaries increase the chance the agent applies this skill in contexts the user did not intend, leading to unnecessary file mutations, network fetches, repository cloning, or data ingestion.
The skill directs the agent to ingest content, download papers, clone repositories, and generate many files in a local knowledge base, but it does not require a prominent user warning or confirmation before making those filesystem changes. This can lead to unexpected local persistence, storage growth, and writes into user workspaces from remote or local inputs.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run_json(cmd):
proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
if proc.returncode != 0:
raise SystemExit(proc.stderr or proc.stdout or f'Command failed: {cmd}')
return json.loads(proc.stdout)
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run_json(cmd):
proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
if proc.returncode != 0:
raise SystemExit(proc.stderr or proc.stdout or f'Command failed: {cmd}')
return json.loads(proc.stdout)
This code resolves a target root, may initialize a repository, ingests content, and optionally runs build and summarization subprocesses that likely write files, but the script provides no confirmation prompt and no user-facing print/log disclosure before those actions occur. For a code file, file-modifying operations should have some visible warning unless clearly disclosed elsewhere, which is not evident in this file.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
DEFAULT_CONFIG = KB_CONFIG_PATH
def run_lint(root: str):
proc = subprocess.run([
'python3', str(KB_LINT), '--root', root
], capture_output=True, text=True, check=False)
if proc.returncode != 0:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def run_prompt_shield(text: str):
if not PSL_SCRIPT.exists():
return {"available": False, "action": "allow", "severity": "SAFE", "reasons": ["psl script missing"], "degraded": False}
proc = subprocess.run(["bash", str(PSL_SCRIPT)], input=text, text=True, capture_output=True, check=False)
output = (proc.stdout or proc.stderr or "").strip()
if not output:
return {"available": True, "action": "warn", "severity": "UNKNOWN", "reasons": ["empty PSL output"], "degraded": True}
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def import_check(module_name: str) -> bool:
proc = subprocess.run([kb_python(), "-c", f"import importlib.util; print(importlib.util.find_spec('{module_name}') is not None)"], capture_output=True, text=True, check=False)
return proc.stdout.strip() == "True"
Repository ingestion performs full git clones of arbitrary URLs, which grants network and external tool execution capabilities beyond what is minimally necessary for a markdown KB entry. In this skill context, user-provided sources are untrusted, so cloning can be abused for internal network probing, oversized content downloads, or unsafe protocol handling through git.
Cloning arbitrary user-supplied repository URLs causes the skill to fetch and store untrusted remote content and invoke an external program against attacker-controlled input. In a KB ingestion context this expands capability beyond simple note capture and can enable SSRF-like internal network access, ingestion of dangerous local git configurations/protocols, or resource exhaustion via large/malicious repositories.
if repo_dir.exists() and any(repo_dir.iterdir()):
return "existing"
repo_dir.parent.mkdir(parents=True, exist_ok=True)
subprocess.run(["git", "clone", "--depth", "1", repo_url, str(repo_dir)], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return "cloned"
The paper ingestion path downloads arbitrary PDFs and processes them with external tools and parsers, including a system strings command. Because PDFs are attacker-controlled and historically parser-targeted, this creates unnecessary exposure for a KB ingestion skill and can lead to denial of service or exploitation of vulnerable parsing dependencies.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
parts.append(txt.strip())
print('\n\n'.join(parts))
"""
proc = subprocess.run([kb_python(), "-c", script, str(pdf_path)], capture_output=True, text=True, check=False)
text = (proc.stdout or "").strip()
if len(text) > 400:
return text
No suspicious patterns detected.