Skip to content

Conversation

@RinZ27
Copy link

@RinZ27 RinZ27 commented Jan 27, 2026

The current implementation of the Run[] builtin and the shell escape (!) in the CLI allows arbitrary command execution through subprocess with shell=True. While this is a core feature for local use, it poses a significant security risk when Mathics is deployed in a sandboxed or remote environment (e.g., a web-based notebook server).

I've introduced a new configuration setting, ENABLE_SYSTEM_COMMANDS, which allows administrators to disable external command execution when necessary. This follows the pattern already established by ENABLE_FILES_MODULE.

Changes:

  • Added ENABLE_SYSTEM_COMMANDS to mathics/settings.py (defaults to True, can be overridden via MATHICS3_ENABLE_SYSTEM_COMMANDS environment variable, and defaults to False if SANDBOX is set).
  • Updated the Run[] builtin in mathics/builtin/system.py to check this setting before execution.
  • Updated the CLI handler in mathics/main.py to respect this setting for the ! escape command.
  • Updated the inspect eval loop in mathics/interrupt.py to respect this setting.
  • When disabled, Run[] will issue a message and return $Failed, and the CLI will display an informative message.

This change provides a much-needed security control for shared or public Mathics instances without impacting the default local experience.

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from db89e25 to 28f1bb1 Compare January 27, 2026 15:55
@mmatera
Copy link
Contributor

mmatera commented Jan 27, 2026

Probably you also want to avoid that 'SetEnvironment' can change environment variables too, as well as writing files.

if len(source_code) and source_code[0] == "!":
subprocess.run(source_code[1:], shell=True)
if not settings.ENABLE_SYSTEM_COMMANDS:
print("Execution of external commands is disabled.")
Copy link
Contributor

Choose a reason for hiding this comment

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

define a message and use evaluation.message instead of print

@mmatera
Copy link
Contributor

mmatera commented Jan 27, 2026

mathics.builtin.system was not modified. @RinZ27, maybe you forgot to commit it.


# Leave this True unless you have specific reason for not permitting
# users to execute system commands.
ENABLE_SYSTEM_COMMANDS = os.environ.get("MATHICS_ENABLE_SYSTEM_COMMANDS", "True").lower() == "true"
Copy link
Member

Choose a reason for hiding this comment

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

We already use in testing the environment variable "SANDBOX" to indicate restricted access.

I guess we should use that here as well. Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

We use SANDBOX=False to avoid tests that need access to the local filesystem. Probably it is also a good idea to avoid the evaluation of these expressions.

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from a8c1196 to d177790 Compare January 28, 2026 10:04
@RinZ27
Copy link
Author

RinZ27 commented Jan 28, 2026

Feedback from the team has been incorporated into the latest push.

ENABLE_SYSTEM_COMMANDS now defaults to False if SANDBOX is active, which I think aligns better with the project\u0027s security model.
evaluation.message("Run", "dis") is being used instead of raw print statements to ensure better engine integration.
Formatting issues were also addressed using the specific black version required.
Hope this addresses all concerns! @rocky @mmatera

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from d177790 to 7b30f89 Compare January 28, 2026 10:13
@mmatera
Copy link
Contributor

mmatera commented Jan 28, 2026

LGTM

# If SANDBOX environment variable is set, this defaults to False.
ENABLE_SYSTEM_COMMANDS = (
os.environ.get(
"MATHICS_ENABLE_SYSTEM_COMMANDS", str(not os.environ.get("SANDBOX"))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"MATHICS_ENABLE_SYSTEM_COMMANDS", str(not os.environ.get("SANDBOX"))
"MATHICS3_ENABLE_SYSTEM_COMMANDS", str(not os.environ.get("SANDBOX"))

We've been moving to the name Mathics3.

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from 2f24c15 to 7132beb Compare January 28, 2026 16:50
@RinZ27
Copy link
Author

RinZ27 commented Jan 28, 2026

Incorporated the latest suggestions by renaming the setting to MATHICS3_ENABLE_SYSTEM_COMMANDS and restricting SetEnvironment and Breakpoint when system commands are disabled.

Default behavior now correctly respects the SANDBOX environment variable. I also squashed the commits into a single clean one as requested. Everything should be in order now for a final review. @rocky

@rocky
Copy link
Member

rocky commented Jan 28, 2026

Why would one ever want to disable system commands without disabling other access, such as information about the process environment? Aren't those also security access problems?

Looking at the code, I see that this sandbox thing, from a security standpoint, is lacking. We should remove the builtin functions ProcessId, ParentProcess, and stuff like that. And then the doctest marks S> are not needed.

More broadly, are we interested in ! in the mathics3 script, or are we interested in running more safely in sandboxed environments?

One other thing, we should be using a less generic name than SANDBOX, e.g. MATHIC3_SANDBOX is what I'd suggest.

@RinZ27 Are you up for making those changes?

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from 7132beb to 74b68dd Compare January 28, 2026 17:28
@RinZ27
Copy link
Author

RinZ27 commented Jan 28, 2026

I completely agree that a robust sandbox should restrict more than just shell execution. I've updated the logic to use the more specific MATHICS3_SANDBOX environment variable and expanded the restrictions to include several builtins that reveal system or process information, such as ProcessID, ParentProcessID, UserName, MachineName, and environment variable access. This makes the security control much more meaningful for remote or shared deployments. @rocky

@rocky
Copy link
Member

rocky commented Jan 28, 2026

It looks like $Breakpoint and $CommandLine need to be added to commands that do not work in a sandboxed environment.

@mmatera
Copy link
Contributor

mmatera commented Jan 28, 2026

It seems the docstring test in '$CommandLine' should be adjusted (remove the curly brackets in the expected result), or just change the behavior when SANDBOX is false, and return an empty list.

@RinZ27
Copy link
Author

RinZ27 commented Jan 29, 2026

I've incorporated the latest feedback.

$CommandLine and $ScriptCommandLine now return an empty list when system commands are disabled, which fixes the docstring tests and aligns with what @mmatera suggested, also expanded the sandbox restrictions to include $SystemMemory, MemoryAvailable[], and blocked the debugger command in the interrupt handler. This should provide a much tighter security boundary for sandboxed environments. @rocky @mmatera

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from 7cb5f0d to 69c7360 Compare January 29, 2026 04:49
Copy link
Contributor

Choose a reason for hiding this comment

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

Mark this as SandBox test (>> -> S>)

Copy link
Contributor

Choose a reason for hiding this comment

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

Also here.

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from 69c7360 to e134a76 Compare January 29, 2026 10:28
@RinZ27
Copy link
Author

RinZ27 commented Jan 29, 2026

I've updated the PR to address the latest feedback:

  • Updated the docstring tests for Breakpoint[], $CommandLine, and $ScriptCommandLine to use the S> tag for sandbox-specific testing.
  • Adjusted the expected output for $CommandLine and $ScriptCommandLine to be an empty list {} when in sandbox mode, which matches the current implementation and fixes the docstring tests. @rocky @mmatera

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from e134a76 to 0fc2c86 Compare January 29, 2026 12:42
@RinZ27
Copy link
Author

RinZ27 commented Jan 29, 2026

Adjusted the parser logic to handle the new Mathics-Scanner 2.0 data structures, as they were breaking the CI. @rocky @mmatera, I also updated the doctest runner to recognize the MATHICS3_SANDBOX flag for skipping restricted tests. Pyodide builds should be passing now.

@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch 3 times, most recently from 946ab2a to 4111647 Compare January 29, 2026 14:16
@RinZ27 RinZ27 force-pushed the security/sandbox-system-commands branch from 4111647 to 3a11687 Compare January 30, 2026 04:26
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.

3 participants