forked from claw/flaskpaste
security: implement pentest remediation (RATE-002, CLI-001)
RATE-002: Proactive rate limit cleanup when entries exceed threshold - Add RATE_LIMIT_CLEANUP_THRESHOLD config (default 0.8) - Trigger cleanup before hitting hard limit - Prevents memory exhaustion under sustained load CLI-001: Validate clipboard tool paths against trusted directories - Add TRUSTED_CLIPBOARD_DIRS for Unix system paths - Add TRUSTED_WINDOWS_PATTERNS for Windows validation - Reject tools in user-writable locations (PATH hijack prevention) - Use absolute paths in subprocess calls
This commit is contained in:
@@ -267,3 +267,75 @@ class TestRateLimitMaxEntries:
|
||||
finally:
|
||||
app.config["RATE_LIMIT_MAX_ENTRIES"] = original_max
|
||||
reset_rate_limits()
|
||||
|
||||
|
||||
class TestRateLimitCleanupThreshold:
|
||||
"""Tests for RATE-002: automatic cleanup trigger when threshold exceeded."""
|
||||
|
||||
def test_cleanup_threshold_config_exists(self, app):
|
||||
"""RATE_LIMIT_CLEANUP_THRESHOLD config should exist."""
|
||||
assert "RATE_LIMIT_CLEANUP_THRESHOLD" in app.config
|
||||
threshold = app.config["RATE_LIMIT_CLEANUP_THRESHOLD"]
|
||||
assert isinstance(threshold, float)
|
||||
assert 0.0 < threshold <= 1.0
|
||||
|
||||
def test_proactive_cleanup_at_threshold(self, app):
|
||||
"""Cleanup triggers proactively when threshold exceeded."""
|
||||
from app.api.routes import (
|
||||
_rate_limit_requests,
|
||||
check_rate_limit,
|
||||
reset_rate_limits,
|
||||
)
|
||||
|
||||
reset_rate_limits()
|
||||
|
||||
original_max = app.config.get("RATE_LIMIT_MAX_ENTRIES", 10000)
|
||||
original_threshold = app.config.get("RATE_LIMIT_CLEANUP_THRESHOLD", 0.8)
|
||||
|
||||
# Set max to 10, threshold to 0.5 (cleanup at 5 entries)
|
||||
app.config["RATE_LIMIT_MAX_ENTRIES"] = 10
|
||||
app.config["RATE_LIMIT_CLEANUP_THRESHOLD"] = 0.5
|
||||
|
||||
try:
|
||||
with app.app_context():
|
||||
# Add 6 entries (exceeds 50% threshold of 10)
|
||||
for i in range(6):
|
||||
check_rate_limit(f"10.0.0.{i}", authenticated=False)
|
||||
|
||||
# Threshold cleanup should have triggered, reducing count
|
||||
# Cleanup prunes to threshold/2 = 2-3 entries
|
||||
assert len(_rate_limit_requests) < 6
|
||||
finally:
|
||||
app.config["RATE_LIMIT_MAX_ENTRIES"] = original_max
|
||||
app.config["RATE_LIMIT_CLEANUP_THRESHOLD"] = original_threshold
|
||||
reset_rate_limits()
|
||||
|
||||
def test_no_cleanup_below_threshold(self, app):
|
||||
"""No cleanup when below threshold."""
|
||||
from app.api.routes import (
|
||||
_rate_limit_requests,
|
||||
check_rate_limit,
|
||||
reset_rate_limits,
|
||||
)
|
||||
|
||||
reset_rate_limits()
|
||||
|
||||
original_max = app.config.get("RATE_LIMIT_MAX_ENTRIES", 10000)
|
||||
original_threshold = app.config.get("RATE_LIMIT_CLEANUP_THRESHOLD", 0.8)
|
||||
|
||||
# Set max to 20, threshold to 0.8 (cleanup at 16 entries)
|
||||
app.config["RATE_LIMIT_MAX_ENTRIES"] = 20
|
||||
app.config["RATE_LIMIT_CLEANUP_THRESHOLD"] = 0.8
|
||||
|
||||
try:
|
||||
with app.app_context():
|
||||
# Add 5 entries (below 80% threshold of 20 = 16)
|
||||
for i in range(5):
|
||||
check_rate_limit(f"10.0.0.{i}", authenticated=False)
|
||||
|
||||
# All 5 entries should remain (no cleanup triggered)
|
||||
assert len(_rate_limit_requests) == 5
|
||||
finally:
|
||||
app.config["RATE_LIMIT_MAX_ENTRIES"] = original_max
|
||||
app.config["RATE_LIMIT_CLEANUP_THRESHOLD"] = original_threshold
|
||||
reset_rate_limits()
|
||||
|
||||
Reference in New Issue
Block a user