Skip to content

[Bug]: 5 reproducible runtime crashes in agent.py scripts (found by executing all 809 skills) #103

Description

@rioujikaji

Summary

While evaluating the skill catalog, I executed every skills/*/scripts/agent.py (809 scripts) once via subprocess on Python 3.14 (Linux/WSL2, Ubuntu) and again on Python 3.12 (Windows). Most scripts behave as expected (run on built-in demo data, or exit cleanly asking for an input artifact / API key). This report collects 5 genuine, reproducible runtime defects — code bugs independent of missing dependencies, missing input, or missing credentials.

Two of them (#1, #2) fail at module import, so the affected skill cannot start at all.

I verified each on Linux with the relevant libraries installed, so these are not "missing dependency" artifacts. Happy to open a PR if useful.

# Skill File:Line Error When
1 configuring-snort-ids-for-intrusion-detection scripts/agent.py:17 NameError: name 'DAQ_DIR' is not defined import time (always)
2 deploying-ransomware-canary-files scripts/agent.py:281 NameError: name 'FileSystemEventHandler' is not defined import time, when watchdog not installed
3 analyzing-linux-elf-malware scripts/agent.py:127-129 ValueError: stdout and stderr arguments may not be used with capture_output whenever a target is analyzed
4 monitoring-darkweb-sources scripts/agent.py:149 KeyError: 'name' default run (no HIBP API key)
5 performing-log-analysis-for-forensic-investigation scripts/agent.py:191/194 ValueError: dict contains fields not in fieldnames: 'service', 'host', 'message' when parsing syslog + another source together

1. configuring-snort-ids — self-referential default (NameError at import)

# line 13-17
SNORT_BIN  = os.environ.get("SNORT_BIN",  "/usr/local/bin/snort")
SNORT_CONF = os.environ.get("SNORT_CONF", "/usr/local/etc/snort/snort.lua")
RULES_DIR  = os.environ.get("SNORT_RULES_DIR", "/usr/local/etc/snort/rules")
LOG_DIR    = os.environ.get("SNORT_LOG_DIR", "/var/log/snort")
DAQ_DIR    = os.environ.get("SNORT_DAQ_DIR", DAQ_DIR)   # <-- DAQ_DIR used as its own default

DAQ_DIR is referenced as its own fallback before it exists. The other four vars use a literal default; this one was likely a copy/paste miss.

Fix: give it a literal default like the others, e.g.

DAQ_DIR = os.environ.get("SNORT_DAQ_DIR", "/usr/local/lib/daq")

2. deploying-ransomware-canary-files — unguarded class base (NameError at import)

# line 22-24
try:
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler
except ImportError:
    ...  # import guarded
...
# line 281 (module scope)
class CanaryFileHandler(FileSystemEventHandler):   # <-- base undefined if watchdog missing

The import is guarded, but the class inherits FileSystemEventHandler at module scope, so when watchdog is absent the module raises NameError at load — before any friendly "pip install watchdog" message can print.

Fix: guard the class (or the whole watchdog-dependent block), e.g.

_Base = FileSystemEventHandler if HAS_WATCHDOG else object
class CanaryFileHandler(_Base):
    ...

or declare watchdog a hard requirement and fail with a clear message.

3. analyzing-linux-elf-malware — invalid subprocess.run args (ValueError on every analysis)

# check_packing(), line 127-129
stdout, _, _ = subprocess.run(["upx", "-t", filepath],
                               capture_output=True, text=True,
                               stderr=subprocess.STDOUT, timeout=120).stdout, "", 0

subprocess.run rejects stderr= together with capture_output=True. This raises unconditionally as soon as check_packing() runs (i.e. any real ELF target), before UPX is even invoked.

Fix: drop stderr=subprocess.STDOUT (capture_output already captures stderr):

proc = subprocess.run(["upx", "-t", filepath], capture_output=True, text=True, timeout=120)
stdout = proc.stdout

4. monitoring-darkweb-sources — hard key access on optional field (KeyError)

# line 149
lines.append(f"  - {b['name']} ({b['breach_date']}) - {b['pwn_count']:,} accounts")

On the default run (no HIBP API key), the breach records passed to the report do not carry a name key, so this crashes. Note lines 43-44 already use .get(...) defensively for the same records.

Fix: be consistent and defensive:

lines.append(f"  - {b.get('name','Unknown')} ({b.get('breach_date','?')}) - {b.get('pwn_count',0):,} accounts")

5. performing-log-analysis-for-forensic-investigation — CSV fieldnames from first row only (ValueError)

# line 191
writer = csv.DictWriter(f, fieldnames=list(timeline[0].keys()))
writer.writeheader()
for event in timeline:
    # line 194
    writer.writerow({k: str(v)[:200] for k, v in event.items()})

fieldnames is derived from timeline[0] only. When the timeline mixes event types (e.g. syslog entries add service, host, message that the first event lacks), writerow raises. Reproduced by passing both a syslog and another source.

Fix: compute the union of keys, or ignore extras:

fieldnames = sorted({k for e in timeline for k in e})
writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")

Reproduction

python3 skills/configuring-snort-ids-for-intrusion-detection/scripts/agent.py    # NameError at import
python3 skills/deploying-ransomware-canary-files/scripts/agent.py                # NameError at import (no watchdog)
python3 skills/analyzing-linux-elf-malware/scripts/agent.py /bin/ls              # ValueError in check_packing
python3 skills/monitoring-darkweb-sources/scripts/agent.py                       # KeyError: 'name'

Environment: Python 3.14.4 (Ubuntu/WSL2) and Python 3.12 (Windows); libraries pyelftools, scapy, pefile, boto3, requests, watchdog(absent for #2) as relevant.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions