Example JSON Validations#
This notebook demonstrates how to check security aspects of a JSON file using a single function call from the fileaudit package:
from fileaudit.json_check import validate_json
Why validate JSON for security?#
JSON files (especially from untrusted sources or remote URLs) can be abused for:
Denial-of-Service via deep nesting — Extremely nested objects/arrays can cause stack overflows or excessive recursion during parsing.
Memory exhaustion — Very large files can consume huge amounts of RAM when loaded.
Invalid / malicious content — Syntax errors or unexpected structure.
Insecure remote fetches — Only HTTPS should be allowed for remote JSON.
The validate_json helper protects against these by enforcing:
Maximum nesting depth (default: 50)
Maximum file size (default: 10 MiB)
Valid JSON syntax
File existence / reachability
HTTPS-only for remote URLs
It works in two modes:
Direct call —
validate_json("path/to/file.json")→ returnsTrue/FalseDecorator — automatically validates a path argument before your function runs
from fileaudit.json_check import validate_json, DEFAULT_MAX_DEPTH, DEFAULT_MAX_FILE_SIZE
from pathlib import Path
import json
print(f"Default max depth : {DEFAULT_MAX_DEPTH}")
print(f"Default max size : {DEFAULT_MAX_FILE_SIZE:,} bytes ({DEFAULT_MAX_FILE_SIZE / 1024 / 1024:.1f} MiB)")
Default max depth : 50
Default max size : 10,485,760 bytes (10.0 MiB)
1. Create sample JSON files#
We prepare a few files to demonstrate success and failure cases.
# Working directory for demo files
demo_dir = Path("json_demo_files")
demo_dir.mkdir(exist_ok=True)
# --- Valid, safe JSON ---
valid_json = {
"name": "Alice",
"age": 30,
"skills": ["python", "security", "json"],
"nested": {"level1": {"level2": {"value": 42}}}
}
valid_path = demo_dir / "valid.json"
valid_path.write_text(json.dumps(valid_json, indent=2))
print(f"Created: {valid_path}")
# --- Deeply nested JSON (exceeds a low depth limit) ---
def make_deep_json(depth: int):
obj = {"leaf": True}
for _ in range(depth):
obj = {"nested": obj}
return obj
deep_path = demo_dir / "too_deep.json"
deep_path.write_text(json.dumps(make_deep_json(20)))
print(f"Created: {deep_path} (depth ~20)")
# --- Invalid JSON syntax ---
invalid_path = demo_dir / "invalid.json"
invalid_path.write_text('{ "broken": true, # missing closing brace and trailing comma')
print(f"Created: {invalid_path}")
# --- "Large" file (we will enforce a tiny size limit) ---
large_path = demo_dir / "large.json"
large_content = json.dumps({"data": "x" * 5000})
large_path.write_text(large_content)
print(f"Created: {large_path} ({large_path.stat().st_size} bytes)")
Created: json_demo_files/valid.json
Created: json_demo_files/too_deep.json (depth ~20)
Created: json_demo_files/invalid.json
Created: json_demo_files/large.json (5012 bytes)
2. The one-simple-line check (Direct call mode)#
# ✅ One simple line – validates size, depth, existence and JSON syntax
result = validate_json("json_demo_files/valid.json")
print("Result:", result) # True on success
Result: True
You can also pass custom limits:
# Custom limits
print("With strict depth=5:")
print(validate_json("json_demo_files/valid.json", max_depth=5))
print("\nWith very small size limit:")
print(validate_json("json_demo_files/valid.json", max_file_size=50))
With strict depth=5:
True
With very small size limit:
Exception: FileAudit Security Validation Failed - File size (181 bytes) exceeds maximum limit of 50 bytes
False
3. Failure cases (security checks in action)#
print("=== Too deeply nested (max_depth=10) ===")
print(validate_json("json_demo_files/too_deep.json", max_depth=10))
=== Too deeply nested (max_depth=10) ===
Exception: FileAudit Security Validation Failed - JSON nesting depth exceeded
False
print("\n=== Invalid JSON syntax ===")
print(validate_json("json_demo_files/invalid.json"))
=== Invalid JSON syntax ===
Exception: FileAudit Security Validation Failed - Invalid JSON format: Expecting property name enclosed in double quotes: line 1 column 20 (char 19)
False
print("\n=== File too large (max_file_size=1000) ===")
print(validate_json("json_demo_files/large.json", max_file_size=1000))
=== File too large (max_file_size=1000) ===
Exception: FileAudit Security Validation Failed - File size (5012 bytes) exceeds maximum limit of 1000 bytes
False
print("\n=== Non-existent file ===")
print(validate_json("json_demo_files/does_not_exist.json"))
=== Non-existent file ===
Exception: FileAudit Security Validation Failed - File not found: json_demo_files/does_not_exist.json
False
4. Decorator mode – automatic validation before function execution#
This is especially useful when your functions accept a file path argument.
# Bare decorator – validates the first argument
@validate_json
def process_config(file_path):
data = json.loads(Path(file_path).read_text())
print(f" → Successfully processed config with keys: {list(data.keys())}")
return data
print("Calling with valid file:")
process_config("json_demo_files/valid.json")
Calling with valid file:
→ Successfully processed config with keys: ['name', 'age', 'skills', 'nested']
{'name': 'Alice',
'age': 30,
'skills': ['python', 'security', 'json'],
'nested': {'level1': {'level2': {'value': 42}}}}
# Decorator with custom limits
@validate_json(max_depth=5, max_file_size=2000)
def load_settings(path):
print(f" → Loading settings from {path}")
return json.loads(Path(path).read_text())
print("Calling with valid (but slightly nested) file and strict depth=5:")
try:
load_settings("json_demo_files/valid.json")
except Exception as e:
print(f"Caught expected error: {type(e).__name__}: {e}")
Calling with valid (but slightly nested) file and strict depth=5:
→ Loading settings from json_demo_files/valid.json
# Target a specific argument by name
@validate_json("config_path", max_depth=30)
def run_pipeline(config_path, dry_run=False):
print(f" → Running pipeline (dry_run={dry_run}) with config {config_path}")
return True
print("Named argument targeting:")
run_pipeline(config_path="json_demo_files/valid.json", dry_run=True)
Named argument targeting:
→ Running pipeline (dry_run=True) with config json_demo_files/valid.json
True
5. Remote HTTPS JSON (also supported)#
Only https:// URLs are accepted. The function first checks Content-Length via HEAD when possible.
# Public example JSON (GitHub raw)
remote_url = "https://jsonplaceholder.typicode.com/todos/1"
print("Validating remote HTTPS JSON:")
print(validate_json(remote_url, max_file_size=10_000))
print("\nHTTP (insecure) is rejected:")
print(validate_json("http://example.com/data.json"))
Validating remote HTTPS JSON:
True
HTTP (insecure) is rejected:
Exception: FileAudit Security Validation Failed - Unsupported URL scheme 'http': only 'https' is allowed.
False
Summary#
With a single import and one function call you get robust security checks for JSON files:
from fileaudit.json_check import validate_json
# Direct
ok = validate_json("path/to/file.json", max_depth=20, max_file_size=1_000_000)
# Or as a decorator
@validate_json(max_depth=20)
def my_func(json_path):
...
This protects against deep-nesting attacks, oversized payloads, invalid syntax, and insecure remote fetches — all with minimal code.