T09 · Insecure Skill Coding Practices
- Location
scripts/register_surface.py:969- Finding
Automatic Execution of Untrusted Deck Sidecar Files During Mandatory Validation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/register_surface.py:969-995
Vulnerability Type: Untrusted Python module execution
Risk Level: HighRelated call-chain evidence:
SKILL.md:2850-2852requires the gate for every hand-off.scripts/check_register_guard.py:182loads kits from the directory containing the selected PPTX.references/security-and-capabilities.md:65-69explicitly acknowledges that checking an externally supplied deck executes adjacentsurface_*.pyfiles.
Vulnerable code:
python KIT_GLOB = "surface_*.py" # a deck's own kits live beside it, under this name def load_kits(directory, *, quiet=False): """Import every `surface_*.py` beside a deck, so its INVENTED registers exist in this process. Registration happens at import time, which means a kit only exists where its file was imported. The gates do not run inside the build — they run afterwards, in a fresh process — so a bespoke register's declared prohibitions were being enforced exactly nowhere. Measured with a scaffolded kit that forbids gradients and a deck that draws one: caught in-process, and reported by the real gate as "a bespoke look has no FORBIDS to check". A capability that exists in the library and not at hand-off is the shape this repo keeps re-learning. Returns `(loaded, errors)`. It never raises: a kit that fails to import must produce a NOTE on the gate, not a traceback that reads like a broken deck. """ import importlib.util directory = Path(os.path.expanduser(str(directory))) loaded, errors = [], [] try: files = sorted(directory.glob(KIT_GLOB)) except OSError as exc: return loaded, ["cannot list {}: {}".format(directory, exc)] for f in files: mod = "slide_maker_kit_" + re.sub(r"[^a-z0-9_]+", "_", f.stem.lower()) try: spec = importlib.util.spec_from_file_locati ...[truncated 3414 chars]- Remediation
View remediation
Remediation Suggestions
- Disable automatic sidecar imports for external decks. Treat
surface_*.pyas executable plugins rather than presentation assets, and reject or ignore them by default during review and redesign workflows. - Require explicit, enforceable authorization. Add an opt-in argument that names each exact kit to load. Do not rely only on prose instructing the Agent to inspect files.
- Bind trusted kits to the deck record. Store the approved relative path and a cryptographic hash in a generated manifest, then verify both immediately before loading.
- Restrict path resolution. Require plain filenames, reject symlinks, resolve the target path, and verify it remains in the intended deck directory.
- Separate validation from execution. Where possible, represent register constraints in a declarative format such as validated JSON instead of executable Python.
- Sandbox unavoidable plugin execution. Run approved kits in a separate process with no network access, a minimal environment, no inherited credentials, restricted filesystem access, resource limits, and a narrowly defined output protocol.
- Change the gate behavior. If unexpected
surface_*.pyfiles are present, fail safely and report their names rather than importing them. - Add regression tests. Verify that a deck received from an untrusted folder cannot cause adjacent Python to execute unless the exact file and hash have been explicitly approved.
- Disable automatic sidecar imports for external decks. Treat
