A secure, versatile, and sandboxed Python code execution service exposed via a simple RESTful API. This project allows you to safely execute untrusted Python code in an isolated environment, complete with support for file attachments, standard input, and retrieving output files.
This project was created with two main goals in mind:
- AI Agents – Safely run dynamic Python code for automation, reasoning, and experimentation.
- Small Python Projects – A lightweight environment to test and share scripts securely.
You can try out the sandbox instantly on the hosted demo server:
Base URL: https://python-exeution.onrender.com
- A user-friendly web interface and documentation are available at the base URL.
- This demo is rate-limited and provided mainly for testing and exploration.
- For stable usage, we recommend running the server locally or deploying it yourself as an admin.
Note: The public API is open to everyone but is rate-limited to ensure fair usage and server stability. Please see the Limits & Restrictions section for more details.
- Secure Sandboxing: Code is executed in an isolated, temporary environment with no network access and restricted filesystem permissions.
- File I/O: Attach files to your request, process them in your script, and retrieve generated output files, all in a single API call.
- Resource Limiting: Strict limits on execution time, code length, and process creation prevent abuse and infinite loops.
- Curated Libraries: Access a safe, curated list of popular libraries like
numpyandPillow, while blocking dangerous modules likeosorsubprocess. - Admin Bypass: Use a secret API key to bypass all public rate limits and import restrictions for trusted administrative tasks.
- Detailed Responses: Get rich context with every request, including your current quota, server load, and request metadata.
- Robust Rate Limiting: Per-IP rate limiting and daily quotas to prevent spam and ensure fair usage.
- Concurrency Control: The server actively manages load, returning a
503 Service Busyerror if too many processes are running concurrently.
Security is the primary design goal. Every execution is constrained by:
- No Network Access: Scripts are blocked from making any outbound network calls.
- Filesystem Isolation: Code runs within a temporary directory that is permanently deleted after execution. Path traversal attacks are prevented, ensuring no access to the host filesystem.
- Import Restrictions: An allowlist of safe modules prevents the use of potentially harmful libraries.
- Process Limits: Protection against "fork bombs" by limiting the number of child processes a script can create.
- Ephemeral Environment: The entire execution context is destroyed after each API call, ensuring no data persists between requests.
- Robust IP Detection: Correctly identifies user IPs even behind a reverse proxy by trusting the
X-Forwarded-Forheader.
Executes the provided Python code in a sandboxed environment.
| Field | Type | Required | Description |
|---|---|---|---|
code |
String | Yes | The Python code to execute (max 2000 characters). |
api_key |
String | No | An admin API key to bypass public limits. |
stdin_data |
String | No | Text data to be passed to the script's standard input. |
attachments |
Array of Objects | No | Files to be made available to the script. Max 2 files, 8MB each. See object schema below. |
return_files |
Array of Strings | No | A list of filenames generated by the script that you want returned in the response. |
Attachment Object Schema:
filename(String): The name of the file as it will appear in the execution directory.content_base_64(String): The file content, encoded in Base64.
All examples use curl for simplicity. The base URL is https://python-exeution.onrender.com/execute.
This is the simplest use case, sending only the code field.
curl -X POST https://python-exeution.onrender.com/execute \
-H "Content-Type: application/json" \
-d '{
"code": "print(f\"The sum is {10 + 25}\")"
}'Use the stdin_data field to pass data to your script.
curl -X POST https://python-exeution.onrender.com/execute \
-H "Content-Type: application/json" \
-d '{
"code": "import sys\nname = sys.stdin.read().strip()\nprint(f\"Hello, {name}!\")",
"stdin_data": "Alice"
}'Provide files in the attachments array. The content must be Base64 encoded.
# First, create a sample file and encode it
echo "This is some sample data." > data.txt
B64_CONTENT=$(base64 -w 0 data.txt)
# Now, make the API call
curl -X POST https://python-exeution.onrender.com/execute \
-H "Content-Type: application/json" \
-d '{
"code": "with open(\"input.txt\", \"r\") as f:\n print(f.read().upper())",
"attachments": [
{
"filename": "input.txt",
"content_base_64": "'"$B64_CONTENT"'"
}
]
}'Use return_files to specify which files created by your script should be sent back in the response.
curl -X POST https://python-exeution.onrender.com/execute \
-H "Content-Type: application/json" \
-d '{
"code": "with open(\"result.txt\", \"w\") as f:\n f.write(\"Process completed successfully.\")",
"return_files": ["result.txt"]
}'The response will contain the Base64-encoded content of result.txt inside the execution_details.output_files object.
Include the api_key to bypass rate limits and import restrictions. This allows you to use powerful modules like os.
curl -X POST https://python-exeution.onrender.com/execute \
-H "Content-Type: application/json" \
-d '{
"code": "import os\nprint(f\"Running with {os.cpu_count()} CPU cores available.\")",
"api_key": "your-secret-api-key-here"
}'A successful response contains metadata about the request, the user's quota, server status, and the complete execution result.
{
"status": "success",
"timestamp_utc": "2024-03-15T10:30:00.123456+00:00",
"user_info": {
"ip_address": "192.0.2.1",
"daily_quota_limit": 30,
"requests_today": 5,
"requests_remaining_today": 25
},
"server_status": {
"load": "normal",
"active_processes_at_request": 0,
"max_concurrent_processes": 5
},
"request_context": {
"code_length": 150,
"attachment_count": 1,
"stdin_provided": false,
"processed_attachments": [
{ "filename": "input.txt", "size_bytes": 1024 }
]
},
"execution_details": {
"success": true,
"stdout": "Process finished.\n",
"stderr": "",
"exit_code": 0,
"execution_duration_sec": 0.0456,
"output_files": {
"result.txt": {
"content_base64": "SGVsbG8sIFdvcmxkIQ==",
"size_bytes": 13
}
}
}
}| Top-Level Field | Description |
|---|---|
status |
Indicates the overall outcome. Always "success" for 200 OK. |
timestamp_utc |
ISO 8601 timestamp of when the response was generated. |
user_info |
An object containing details about the user's quota. For admins, shows rate_limits_applied: false. |
server_status |
Information about the server's load at the time of the request. |
request_context |
Metadata about the request payload that was processed. |
execution_details |
A detailed object containing the full output from the code execution. |
Errors are returned with an appropriate HTTP status code and include user and server context where possible.
Example: Rate Limit Exceeded (429)
{
"status": "error",
"timestamp_utc": "2024-03-15T11:00:00.987654+00:00",
"error_details": {
"type": "RateLimitExceeded",
"message": "Daily quota of 30 exceeded."
},
"user_info": {
"ip_address": "192.0.2.1",
"daily_quota_limit": 30,
"requests_today": 30,
"requests_remaining_today": 0
}
}| Status Code | Error Type | Reason |
|---|---|---|
400 |
ValidationError |
Request JSON is malformed, a file is too large, etc. |
400 |
ForbiddenImportError |
The script attempts to import a disallowed module. |
400 |
TimeoutError |
Execution exceeded the 10-second time limit. |
429 |
RateLimitExceeded |
The per-minute or daily request limit has been reached. |
503 |
ServerBusy |
The server has reached its maximum concurrent execution limit. |
| Category | Limit | Description |
|---|---|---|
| Rate Limits | 5 RPM / 30 RPD | Requests per minute / Requests per day, per IP address. |
| 5 Concurrent Jobs | Max simultaneous executions server-wide. | |
| Resources | 10 seconds | Maximum execution time per script. |
| 2000 chars | Maximum length of the code field. |
|
| 10 child processes | Protection against fork bombs. | |
| Files | 2 attachments | Maximum number of files that can be uploaded in one request. |
| 8 MB per file | Maximum size for each attached or returned file. |
| Category | Allowed Modules |
|---|---|
| Key Third-Party | numpy |
| Media & Document Gen | PIL (Pillow), reportlab, fpdf |
| Data, Math & Time | math, statistics, decimal, random, datetime, time |
| Text, Regex & Data | string, re, textwrap, json, ast, base64, hashlib, uuid, secrets |
| Data Structures & Utils | collections, itertools, functools, operator, copy, pprint, typing |
This example uploads an image, uses the Pillow library to convert it to grayscale, and returns the processed image.
import requests
import base64
import json
API_URL = 'https://python-exeution.onrender.com/execute'
LOCAL_IMAGE_PATH = 'my_photo.jpg' # Make sure this file exists locally
RESULT_IMAGE_PATH = 'result_grayscale.png'
# This script is sent in the 'code' field
sandbox_code = """
from PIL import Image
try:
with Image.open('input_photo.jpg') as img:
grayscale_img = img.convert('L')
grayscale_img.save('output_grayscale.png')
print("Image successfully converted to grayscale.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
"""
# 1. Read local image and Base64 encode it
try:
with open(LOCAL_IMAGE_PATH, "rb") as image_file:
b64_content = base64.b64encode(image_file.read()).decode('utf-8')
except FileNotFoundError:
print(f"Error: Make sure a file named '{LOCAL_IMAGE_PATH}' exists.")
exit()
# 2. Construct the API payload
payload = {
"code": sandbox_code,
"attachments": [{"filename": "input_photo.jpg", "content_base_64": b64_content}],
"return_files": ["output_grayscale.png"]
}
# 3. Send the request
response = requests.post(API_URL, json=payload)
response_data = response.json()
# 4. Process the new, detailed response structure
print(f"API Response Code: {response.status_code}")
if response.status_code == 200:
print("API Call Successful!")
user_info = response_data.get('user_info', {})
exec_details = response_data.get('execution_details', {})
print(f" > Requests remaining today: {user_info.get('requests_remaining_today', 'N/A')}")
print(f" > Stdout: {exec_details.get('stdout', '').strip()}")
output_files = exec_details.get('output_files', {})
file_info = output_files.get('output_grayscale.png', {})
b64_image_content = file_info.get('content_base64')
if b64_image_content:
grayscale_data = base64.b64decode(b64_image_content)
with open(RESULT_IMAGE_PATH, "wb") as f:
f.write(grayscale_data)
print(f" > Success! Grayscale image saved to '{RESULT_IMAGE_PATH}'")
else:
print(f" > Error returning file: {file_info.get('error', 'Unknown file error')}")
else:
print("API Error Details:")
print(json.dumps(response_data, indent=2))Click the button above, sign up on Render, and provide the repository URL:
https://github.com/Bhargavxyz738/Python_exeution.git
Render will automatically clone the repository, set everything up, and run the app using:
gunicorn main:app
- Python 3.8+
pipandvenv
-
Clone the repository:
git clone https://github.com/Bhargavxyz738/Python_exeution.git cd Python_exeution -
Create and activate a virtual environment:
# For Unix/macOS python3 -m venv venv source venv/bin/activate # For Windows python -m venv venv .\venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
For admin access, set the PYTHON_EXE_KEY environment variable.
# For Unix/macOS
export PYTHON_EXE_KEY="your-secret-api-key"
# For Windows (in Command Prompt)
set PYTHON_EXE_KEY="your-secret-api-key"# For development (uses the simple Flask server)
python main.py
# For production-like testing (uses Gunicorn)
gunicorn main:appThe server will start on http://127.0.0.1:5000.
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
This project is licensed under the MIT License.
- Bhargav - Bhargavxyz738