{"id":26349579,"url":"https://github.com/lemonyte/safe-exec","last_synced_at":"2025-10-12T08:07:21.041Z","repository":{"id":281310963,"uuid":"944894734","full_name":"lemonyte/safe-exec","owner":"lemonyte","description":"Deobfuscate and inspect code passed into exec() and eval()","archived":false,"fork":false,"pushed_at":"2025-10-06T20:06:19.000Z","size":45,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-06T21:23:56.398Z","etag":null,"topics":["cybersecurity","deobfuscation","deobfuscator","eval","exec","malware-detection","python","security"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/safe-exec","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lemonyte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-08T07:15:37.000Z","updated_at":"2025-10-06T19:36:32.000Z","dependencies_parsed_at":"2025-05-01T21:39:45.709Z","dependency_job_id":"2c914a83-4e22-4083-92c0-cccc737088d0","html_url":"https://github.com/lemonyte/safe-exec","commit_stats":null,"previous_names":["lemonyte/safe-exec"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/lemonyte/safe-exec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fsafe-exec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fsafe-exec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fsafe-exec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fsafe-exec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lemonyte","download_url":"https://codeload.github.com/lemonyte/safe-exec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonyte%2Fsafe-exec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279010800,"owners_count":26084807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cybersecurity","deobfuscation","deobfuscator","eval","exec","malware-detection","python","security"],"created_at":"2025-03-16T09:18:48.428Z","updated_at":"2025-10-12T08:07:21.006Z","avatar_url":"https://github.com/lemonyte.png","language":"Python","readme":"# safe-exec\n\n`safe-exec` provides a context manager that prevents calls to `exec` and `eval` in Python code, and reveals the code in calls that were attempted.\n\nThis is useful for retrieving deobfuscated code from obfuscated malware samples that use `exec` or `eval` as the entry point.\n\n\u003e [!CAUTION]\n\u003e **This package does not guarantee that a script is safe to run**. It is only a tool to help deobfuscate code. It does **not** sandbox code, nor does it intend to be foolproof. Never run potentially malicious code outside of a secure sandboxed environment.\n\n## Installation\n\n```shell\npip install safe-exec\n```\n\nOr install from source:\n\n```shell\npip install git+https://github.com/lemonyte/safe-exec.git\n```\n\nPython versions 3.9 through 3.13 are supported.\n\n## Simple example\n\nThe `safe` context manager takes either `exec` or `eval` as an argument.\n\n```python\n\u003e\u003e\u003e from safe_exec import safe\n\u003e\u003e\u003e with safe(exec):\n...     from base64 import b64decode\n...     exec(b64decode(\"cHJpbnQoJ29iZnVzY2F0ZWQgY29kZScp\"))\n\nsafe_exec.ExecBlockedError: blocked execution of b\"print('obfuscated code')\"\n```\n\nYou can also use the `runpy` module to execute a different script in the `safe` context:\n\n```python\n\u003e\u003e\u003e import runpy\n\u003e\u003e\u003e with safe(exec), safe(eval):\n...     runpy.run_path(\"path/to/script.py\")\n```\n\n## Advanced usage\n\n`safe` can also be used as a decorator to block calls to `exec` or `eval` in a function:\n\n```python\nfrom safe_exec import safe\n\n@safe(exec)\n@safe(eval)\ndef untrusted_func():\n    exec(\"print('This is an untrusted function')\")\n\nuntrusted_func()\n```\n\nAnd as a function to register a third-party function as an untrusted caller:\n\n```python\nfrom safe_exec import safe\nimport runpy\n\nrunpy.run_path = safe(exec)(runpy.run_path)\n```\n\nHowever, the context manager is recommended for most use cases, as it ensures the functions that are overwritten are restored after the context exits.\n\n### Allowing certain calls\n\n`safe-exec` provides `allow_exec` and `allow_eval` context decorators to allow specific calls to `exec` and `eval`, respectively.\n\nThese can be used as decorators on functions that should be allowed to call `exec` or `eval`:\n\n```python\nfrom safe_exec import allow_exec, allow_eval\n\n@allow_exec\n@allow_eval\ndef trusted_func():\n    exec(\"print('This is a trusted function')\")\n    eval(\"print('This is a trusted function')\")\n\ntrusted_func()\n```\n\n\u003e [!CAUTION]\n\u003e If other code calls the decorated function, the `exec` and `eval` calls will still be allowed.\n\nAs context managers to temporarily allow a function to call `exec` or `eval`:\n\n```python\nfrom safe_exec import allow_exec, allow_eval\n\ndef semi_trusted_func():\n    exec(\"print('This is a semi-trusted function')\")\n    eval(\"print('This is a semi-trusted function')\")\n\nwith allow_exec(semi_trusted_func), allow_eval(semi_trusted_func):\n    semi_trusted_func()  # Calls are allowed here.\nsemi_trusted_func()  # Calls are blocked here.\n```\n\nOr as functions to register a third-party function as an allowed caller:\n\n```python\nfrom safe_exec import allow_eval\nimport collections\n\nallow_eval(collections.namedtuple)\n```\n\n### `safe` vs `allow_exec` and `allow_eval`\n\nThe two groups of context managers have slightly different purposes, and therefore different interfaces.\n\n`safe` creates a 'safe' context wherein calls to `exec` or `eval` are blocked.\nIf used as a decorator, it does not do anything with the decorated function itself.\n\n`allow_exec` and `allow_eval` on the other hand need to take a callable (besides `exec` or `eval`) as an argument.\nThis is because they register the callable as a trusted caller of `exec` or `eval`, whether they are used as decorators or context managers.\n\n## False positives\n\nBecause `exec` and `eval` are used in a number of places within the Python standard library, `safe-exec` may prevent some necessary code from running. If you encounter a false positive, please [open an issue](https://github.com/lemonyte/safe-exec/issues).\n\nAs a temporary workaround, if you can determine the calling function that depends on `exec` or `eval`, you can use the `allow_exec` and `allow_eval` context managers to register it as a trusted caller.\n\nLegitimate calls to `exec` and `eval` are allowed by inspecting the caller's frame. If the caller's code object is present in the list of trusted callers, the call is allowed. Such calls are logged as informational messages.\n\n```python\n\u003e\u003e\u003e from safe_exec import safe\n\u003e\u003e\u003e import logging\n\u003e\u003e\u003e logging.basicConfig(level=logging.INFO)\n\u003e\u003e\u003e from typing import NamedTuple\n\u003e\u003e\u003e with safe(eval):\n...     Foo = NamedTuple(\"Foo\", [(\"bar\", int)])\n\nINFO:safe_exec:allowed eval call by 'namedtuple' from '.../lib/collections/__init__.py':345\n```\n\n## License\n\n[MIT License](LICENSE.txt)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonyte%2Fsafe-exec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flemonyte%2Fsafe-exec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonyte%2Fsafe-exec/lists"}