Skip to content

disable os acces - #69

Open
helin-ado wants to merge 4 commits into
developfrom
bugfix/disable_os_acces
Open

helin-ado wants to merge 4 commits into
developfrom
bugfix/disable_os_acces

Conversation

@helin-ado

@helin-ado helin-ado commented Oct 28, 2026 •

Copy link
Copy Markdown

Restrict imports in user-supplied filter scripts (PT-HLN-HDP-26A-002, CWE-78)

Problem

Filter scripts were loaded with PyImport_ImportModule / PyImport_ReloadModule, so
they ran with no restrictions. Anyone who can edit a script (including via the
Configurator) could import os, subprocess, socket, ctypes etc. and run
arbitrary OS commands as the Fledge service user.

Changes

  • New include/script_sandbox.h: embedded Python loader (load_script) that
    reads the script source instead of importing it, then
    • runs an AST check before any script code executes: rejects imports outside
      an allow-list, relative/star imports, dunder attribute access
      (__class__, __subclasses__, ...), __import__/__builtins__, and
      eval, exec, compile, open, getattr and similar builtins;
    • executes the script in a fresh module with restricted __builtins__ and an
      __import__ that enforces the same allow-list at run time.
  • python35_filter.cpp / python35.h: new Python35Filter::loadScript(),
    used in configure() and both paths of reconfigure() so scripts are checked on
    start and on every reconfigure. Script names containing / or .. are rejected.
    The loader is released in shutdown().
  • Error logging: logErrorMessage() rewritten with std::string and null-safe
    helpers. Sandbox rejections are logged with the reason and line number. This also
    removes the old unchecked PyBytes_AsString/rindex handling.
  • Fail closed: a rejected script leaves the filter in the failed state and
    readings are dropped.
  • Allow-list: json math cmath time datetime re copy collections itertools functools string decimal fractions statistics numbers random bisect heapq struct base64 binascii hashlib hmac enum typing textwrap unicodedata.
    The deny-list (os subprocess socket sys ctypes importlib shutil io threading multiprocessing pickle urllib http ...) cannot be overridden.
  • Operator-only extension: FLEDGE_PYTHON35_EXTRA_IMPORTS (comma-separated
    exact module names) adds modules. It is read from the service environment, not the
    filter config category, because that category is editable by script authors.
  • Examples/docs: examples/scale35.py and readings35.py no longer import
    os/sys/logging. README gains a "Script restrictions" section.
  • Tests: new PYTHON35.Sandbox* cases in tests/test_python35.cpp.
  • Dev tooling: .ci/deb/Dockerfile, .ci/deb/test.sh, .ci/compose/,
    os/sys/logging. README gains a "Script restrictions" section.
  • Tests: new PYTHON35.Sandbox* cases in tests/test_python35.cpp.
  • Dev tooling: .ci/deb/Dockerfile, .ci/deb/test.sh, .ci/compose/,
    docker-compose.yml, .dockerignore for building and running the tests in a
    container.

Breaking change

Existing scripts that import os, sys, logging or other non-allow-listed
modules will now be rejected and must be updated, or the module must be added via
FLEDGE_PYTHON35_EXTRA_IMPORTS. The old examples/scale35.py was one such script.

Security notes

This is defence in depth, not a complete sandbox. In-process Python restrictions
can be bypassed by a determined author. Fledge should still run with least
privilege, and edit access to filter scripts should be restricted. Any module added
via the env var widens the attack surface (for example, logging can write files).

Testing

  • PYTHON35.Sandbox* unit tests pass
  • Existing filter tests pass
  • Script importing os is rejected and logged, and the filter drops readings
  • Script using only allow-listed modules still works, including after reconfigure

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical sandbox bypasses permit OS-command execution without opt-in, while Python 3.5 incompatibility breaks script loading and missing prerequisite scripts block clean-checkout image builds.

4 open issues
What changed in this PR

This PR adds restricted loading for user-supplied Python filter scripts in Fledge, aiming to reduce access to OS commands and interpreter internals.

Changes:

  • Adds AST validation, restricted builtins, and import allow-lists during configuration and reconfiguration.
  • Updates error logging, examples, documentation, and sandbox regression tests.
  • Adds Docker-based build, test, and development runtime tooling.
File Description
tests/​test_python35.cpp Adds rejection and allowed-script regression tests.
README.rst Documents script restrictions and operator-controlled imports.
readings35.py Removes the unused sys import.
python35_filter.cpp Integrates restricted loading and safer error logging.
include/​script_sandbox.h Defines source validation and restricted execution.
include/​python35.h Declares the loader and its stored Python reference.
examples/​scale35.py Replaces restricted imports and syslog logging with stdout diagnostics.
docker-compose.yml Defines development runtime and test services.
.dockerignore Excludes host build output from Docker contexts.
.ci/​deb/​test.sh Adds a Docker test-build wrapper.
.ci/​deb/​Dockerfile Adds build, test, runtime, and artifact stages.
.ci/​compose/​entrypoint.sh Starts syslog and Fledge, then streams logs.

Review effort: Balanced

Comment thread .ci/deb/Dockerfile Resolved
Comment thread include/script_sandbox.h Resolved
Comment thread include/script_sandbox.h Resolved
Comment thread include/script_sandbox.h Resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants