Back to skill

Security audit

ops-journal

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local ops journal skill, with expected persistence and exports, but users should protect logged operational details and treat exported or untrusted log content carefully.

Install only if you are comfortable keeping operational notes on local disk. Avoid logging credentials or secrets, restrict access to the journal directory, and be careful when exporting to CSV or writing reports to paths that may already contain files.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/journal.py:189
Finding

Terminal Escape-Sequence Injection Through Untrusted Journal Content

Content
View full analysis

Vulnerability Details

File Location: scripts/journal.py:189, 243, 289, 355, 403, 504, 575
Vulnerability Type: Improper neutralization of terminal control sequences
Risk Level: Medium

Vulnerable Code

python
print(f"\033[0;32m✅\033[0m Logged #{entry_id}: {icon} {color}[{severity}]{RESET} {message}")

The same unsafe rendering pattern is used for incident titles, resolutions, and stored messages:

python
print(f"\033[0;31m🔥\033[0m Incident {BOLD}{inc_id}{RESET} opened: {title} [{severity}]")
print(f"\033[0;32m✅\033[0m Incident {BOLD}{inc_id}{RESET} resolved ({duration}m): {resolution}")
print(f"    {DIM}{e['timestamp']}{RESET} {icon} {e['message']}")
print(f"  {DIM}#{r['id']} {r['timestamp']}{RESET} {icon} {sev_color}[{r['severity']}]{RESET} {r['message']}{tags}{inc}")
print(f"    {DIM}{e['timestamp']}{RESET} {icon} {sev_color}[{e['severity']}]{RESET} {e['message']}")
print(f"    {DIM}{e['timestamp']}{RESET} {icon} {sev_c}[{e['severity']}]{RESET} {e['message']}")

Technical Analysis

Journal messages, incident titles, incident resolutions, and tags can originate from command-line arguments or automated monitoring hooks. These values are stored and later inserted directly into terminal output without filtering C0/C1 control characters or ANSI escape sequences.

An attacker who can influence journal content can embed sequences beginning with the escape character. When an operator runs log, incident show, search, summary, or timeline, an ANSI-capable terminal may interpret the embedded bytes as terminal commands rather than visible text.

Possible effects include:

  • Altering text color or cursor position to disguise output.
  • Clearing or overwriting portions of the terminal.
  • Creating deceptive terminal hyperlinks.
  • Forging apparent journal records or command results.
  • Manipulating terminal state until it is reset.

The program intentionally emits its own ANSI sequences, but it does not distinguish those trusted ...[truncated 1346 chars]

Remediation
View remediation

Remediation Suggestions

  1. Introduce a dedicated terminal-sanitization function for every untrusted value rendered in human-readable mode.
  2. Remove or visibly encode the escape character, C0 control characters other than an explicitly permitted newline or tab, DEL, and C1 control characters.
  3. Apply sanitization at output time so raw data can remain available for JSON or other machine-readable consumers when required.
  4. Sanitize all relevant fields consistently, including messages, titles, resolutions, tags, and values read from an existing database.
  5. Consider disabling color when standard output is not a TTY.
  6. Add regression tests using escape sequences for screen clearing, cursor movement, OSC hyperlinks, and terminal-title modification.

Example defensive helper:

python
import re

CONTROL_RE = re.compile(r"[\x00-\x08\x0b-\x1f\x7f-\x9f]")

def safe_terminal_text(value):
    return CONTROL_RE.sub(
        lambda match: f"\\x{ord(match.group(0)):02x}",
        str(value),
    )

Use the sanitized value at every terminal sink:

python
print(safe_terminal_text(message))

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/journal.py:606
Finding

Spreadsheet Formula Injection in CSV Exports

Content
View full analysis

Vulnerability Details

File Location: scripts/journal.py:606-608
Vulnerability Type: CSV/spreadsheet formula injection
Risk Level: Medium

Vulnerable Code

python
writer.writerow(["id", "timestamp", "category", "severity", "message", "tags", "incident_id"])
for r in rows:
    writer.writerow([r["id"], r["timestamp"], r["category"], r["severity"], r["message"], r["tags"], r["incident_id"]])

Technical Analysis

The CSV export writes attacker-influenced messages and tags directly into cells. Python's csv.writer correctly handles CSV delimiters and quoting, but CSV quoting does not prevent spreadsheet applications from interpreting cell values as formulas.

Values beginning with formula-triggering characters such as =, +, -, or @ may be evaluated when an exported file is opened in spreadsheet software. Leading whitespace, tabs, or control characters can also be used to bypass simplistic checks in some spreadsheet applications.

The affected values include at least:

  • message, supplied to the log command.
  • tags, supplied through --tags.
  • Incident-generated messages containing attacker-influenced titles or resolutions.

Attack Path

  1. An attacker causes a journal entry to be created with a message or tag beginning with a spreadsheet formula marker.
  2. The entry is stored in journal.db.
  3. An operator runs:
bash
python3 scripts/journal.py export --format csv --output journal.csv
  1. The application writes the value into the CSV without spreadsheet-specific neutralization.
  2. The operator opens journal.csv in spreadsheet software.
  3. The spreadsheet interprets the cell as a formula rather than inert text.
  4. Depending on the spreadsheet product and security configuration, the formula can display deceptive content, initiate external resource requests, or expose data available within the workbook. More severe legacy formula behaviors are environment-dependent and are not guaranteed by this code alone.

...[truncated 615 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a spreadsheet-safe cell encoder for all attacker-influenced text fields.
  2. Detect formula markers after accounting for leading whitespace and control characters.
  3. Prefix dangerous values with an apostrophe or another spreadsheet-compatible text marker.
  4. Document whether CSV output is intended for spreadsheets or raw machine processing. If both are needed, provide separate raw and spreadsheet-safe modes.
  5. Apply the protection to every textual column rather than only message.
  6. Add tests for values beginning with =, +, -, @, tabs, carriage returns, and combinations of whitespace followed by a formula marker.

Example mitigation:

python
def spreadsheet_safe(value):
    text = "" if value is None else str(value)
    probe = text.lstrip(" \t\r\n")
    if probe.startswith(("=", "+", "-", "@")):
        return "'" + text
    return text

writer.writerow([
    r["id"],
    r["timestamp"],
    spreadsheet_safe(r["category"]),
    spreadsheet_safe(r["severity"]),
    spreadsheet_safe(r["message"]),
    spreadsheet_safe(r["tags"]),
    spreadsheet_safe(r["incident_id"]),
])

If preserving exact raw values is mandatory, export JSON for machine consumption and reserve the neutralized CSV format for spreadsheet use.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (3)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `SKILL.md` — This file

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The timeline --output and export --output paths are taken directly from user input and written with normal open(..., "w") semantics, which will overwrite existing files without confirmation and can write sensitive journal data to unintended locations. In an agent/skill context, this is risky because higher-level automation may pass paths non-interactively, making accidental clobbering or disclosure easier.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly documents persistent storage locations for operational data but does not warn that entries may contain sensitive incident, deployment, or security details that will remain on disk. In an ops context, users may log secrets, internal infrastructure details, or forensic notes, so omission of a retention/privacy warning can lead to unintended exposure through local compromise, backups, shared workstations, or exported artifacts.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.