Machine Rules is a rule engine that evaluates expressions defined in rule files. The security of your application depends on where rules come from and who has access to modify them.
Rules defined by your development team, version-controlled in your repository, and deployed with your application.
Use Case: Application logic, business rules maintained by developers Risk Level: Low - These are equivalent to code in your application
Rules authored by internal users (administrators, business analysts) through controlled interfaces.
Use Case: Configuration, business rules that need to change without code deployment Risk Level: Medium - Requires validation and sandboxing
Rules from external sources, user uploads, or public input.
Use Case: NOT RECOMMENDED Risk Level: Critical - Can lead to arbitrary code execution
The YAML loader uses a safe expression evaluator (via simpleeval) that prevents code injection:
from machine_rules.loader.yaml_loader import YAMLRuleLoader
# Safe: Uses simpleeval sandbox for expression evaluation
execution_set = YAMLRuleLoader.from_file('rules.yaml')What's Allowed:
- β
Arithmetic:
fact.get('value') + 10 - β
Comparisons:
fact.get('age') > 18 - β
Dictionary/list access:
fact['items'][0] - β
Boolean logic:
x > 10 and y < 20 - β
Method calls:
fact.get('name', 'default') - β
Built-in functions:
len(),str(),int(), etc.
What's Blocked:
- β Imports:
__import__('os') - β File operations:
open('/etc/passwd') - β Code execution:
eval(),exec(),compile() - β Dunder access:
__class__,__builtins__ - β System calls:
os.system()
Rules created with Python functions are safe when the functions themselves are trusted:
from machine_rules.api.execution_set import Rule
def check_age(fact):
return fact.get('age', 0) >= 18
def grant_access(fact):
return {'access': 'granted', 'user': fact.get('name')}
rule = Rule(
name="age_verification",
condition=check_age,
action=grant_access
)# Store rules in your repository
git add rules/production_rules.yaml
git commit -m "Update business rules"Treat rule changes like code changes:
- Pull request process
- Peer review
- Automated testing
from machine_rules.security.safe_evaluator import safe_eval, SecurityError
import logging
logger = logging.getLogger(__name__)
def validate_rule_expression(expr: str) -> bool:
"""Validate expression before deployment."""
try:
# Test with dummy data
safe_eval(expr, {'fact': {}})
return True
except SecurityError as e:
logger.error(f"Unsafe expression: {e}")
return False
except Exception as e:
logger.error(f"Invalid expression: {e}")
return FalseIn production:
- Deploy rules as read-only files
- Don't allow runtime rule modification
- Never load rules from user input
import logging
logging.basicConfig(level=logging.WARNING)
# Security errors in rules will be loggedThe safe evaluator (using simpleeval) provides:
- Restricted Namespace: Only specified variables accessible
- No Imports: Cannot load external modules
- No Builtins: No access to
__builtins__ - Pattern Blocking: Rejects dangerous patterns before evaluation
- Exception Handling: Graceful failures without exposing internals
All security errors are logged:
import logging
# Configure logging to track security issues
logging.basicConfig(
level=logging.WARNING,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)The safe evaluator supports a subset of Python:
Supported:
- Arithmetic operators:
+,-,*,/,%,** - Comparison operators:
==,!=,<,>,<=,>= - Boolean operators:
and,or,not - Dictionary/list access:
fact['key'],fact.get('key') - Literals: numbers, strings, lists, dicts
Not Supported:
- Comprehensions:
[x for x in items] - Lambda functions:
lambda x: x + 1 - Complex assignments
- Control flow statements (if/else, for, while)
Workaround: Implement complex logic in custom action functions:
def complex_action(fact):
# Implement complex logic in Python
items = fact.get('items', [])
return [process(item) for item in items if item.active]
rule = Rule(
name="complex_rule",
condition=lambda f: f.get('type') == 'special',
action=complex_action
)Safe evaluation has minimal overhead (~10-20% slower than native eval), but for rule sets with thousands of evaluations per second, consider:
- Caching rule results
- Using programmatic rules (Python functions)
- Profiling with
cProfile
The safe evaluator may need updates for new Python versions. Always test with your target Python version.
DO NOT open public GitHub issues for security vulnerabilities.
Instead, please use one of these methods:
- GitHub Security Advisories: Use the Security tab on the repository
- Email: Contact the maintainers directly through GitHub
Include in your report:
- Description of the vulnerability
- Steps to reproduce
- Impact assessment
- Affected versions
- Suggested fix (if any)
We will respond within 48 hours and provide a timeline for fixes.
- Acknowledge: Confirm receipt within 48 hours
- Assess: Evaluate severity and impact within 1 week
- Fix: Develop and test patch
- Disclose: Coordinate disclosure timeline
- Release: Publish fixed version and security advisory
The DMN/Excel loader (DMNRuleLoader) was completely removed in version 0.2.0 due to irremediable security vulnerabilities:
- Used unsafe
eval()allowing arbitrary code execution - Could not be safely sandboxed
- Presented unacceptable security risk
Migration Path: Use the YAML loader for structured rule data. YAML provides:
- Safe expression evaluation via
simpleeval - Version-controllable plain text format
- Better testing and validation capabilities
- No Excel dependencies
The project uses these dependencies for secure operation:
- simpleeval (>=0.9.13): Safe expression evaluation
- pyyaml (>=6.0): Safe YAML parsing
- pydantic (>=2.0): Data validation
Install core dependencies:
pip install machine-rulesOr with optional API features:
pip install machine-rules[api]simpleeval is a mature, well-audited library used by many projects for safe expression evaluation.
Before deploying to production:
- All rules stored in version control
- Rules loaded from trusted sources only (YAML files or programmatic)
- No rules loaded from user input or untrusted sources
- Logging configured to capture security errors
- Rules tested with security test suite (
pytest machine_rules/tests/test_security.py) - Team trained on rule security best practices
- Monitoring in place for suspicious rule activity
- Incident response plan documented
- Production environment uses read-only rule files
| Version | Date | Security Changes |
|---|---|---|
| 0.2.0 | 2025-12-18 | Added safe evaluator, removed DMN loader, Python 3.9+ requirement |
| 0.1.0 | 2024 | Initial release (unsafe eval in loaders) |
- OWASP - Code Injection
- Python Security Best Practices
- simpleeval Documentation
- Machine Rules Documentation
- Contributing Guidelines
Last Updated: December 18, 2025
Next Review: March 18, 2026