Remove comments indicating FP or TP

This commit is contained in:
Alexander Braml
2026-04-08 15:29:45 +02:00
parent 16838618a3
commit 42cdf985ca
10 changed files with 113 additions and 168 deletions

View File

@@ -1,10 +1,4 @@
"""Cryptography utilities - streamlined version. """Cryptography utilities - streamlined version."""
FINDING CLASSIFICATIONS:
- TRUE POSITIVE (TP): Actual security vulnerability
- FALSE POSITIVE (FP): Flagged but not a real issue in context
- UNCERTAIN: Could be either depending on deployment context
"""
import os import os
import random import random
@@ -22,16 +16,12 @@ from cryptography.hazmat.backends import default_backend
# ============================================================================= # =============================================================================
# TP: Hardcoded production key
PRODUCTION_KEY = b"aK9$mX2#pL7@nQ4&wE8*rT5%yU1!oI3^" PRODUCTION_KEY = b"aK9$mX2#pL7@nQ4&wE8*rT5%yU1!oI3^"
# FP: Example/placeholder key clearly marked
EXAMPLE_KEY = "REPLACE_THIS_KEY_IN_PRODUCTION" EXAMPLE_KEY = "REPLACE_THIS_KEY_IN_PRODUCTION"
# FP: Test key with test prefix
TEST_API_KEY = "test_sk_4eC39HqLyjWDarjtT1zdp7dc" TEST_API_KEY = "test_sk_4eC39HqLyjWDarjtT1zdp7dc"
# UNCERTAIN: Looks real but might be intentionally fake
BACKUP_KEY = "bkp_2024_xK9mP2sL7nQ4wE8rT5yU1oI3aB6cD" BACKUP_KEY = "bkp_2024_xK9mP2sL7nQ4wE8rT5yU1oI3aB6cD"
@@ -41,30 +31,30 @@ BACKUP_KEY = "bkp_2024_xK9mP2sL7nQ4wE8rT5yU1oI3aB6cD"
def generate_session_token_insecure() -> str: def generate_session_token_insecure() -> str:
"""TP: Using random for session token.""" """Using random for session token."""
chars = string.ascii_letters + string.digits chars = string.ascii_letters + string.digits
return "".join(random.choice(chars) for _ in range(32)) return "".join(random.choice(chars) for _ in range(32))
def generate_otp_insecure() -> str: def generate_otp_insecure() -> str:
"""TP: Using random for OTP.""" """Using random for OTP."""
return str(random.randint(100000, 999999)) return str(random.randint(100000, 999999))
def generate_session_token_secure() -> str: def generate_session_token_secure() -> str:
"""FP: Using secrets for session token.""" """Using secrets for session token."""
return secrets.token_urlsafe(32) return secrets.token_urlsafe(32)
def shuffle_playlist(songs: list) -> list: def shuffle_playlist(songs: list) -> list:
"""FP: random is fine for non-security shuffling.""" """random is fine for non-security shuffling."""
result = songs.copy() result = songs.copy()
random.shuffle(result) random.shuffle(result)
return result return result
def roll_dice() -> int: def roll_dice() -> int:
"""FP: random for game mechanics.""" """random for game mechanics."""
return random.randint(1, 6) return random.randint(1, 6)
@@ -74,14 +64,14 @@ def roll_dice() -> int:
def encrypt_ecb(key: bytes, data: bytes) -> bytes: def encrypt_ecb(key: bytes, data: bytes) -> bytes:
"""TP: ECB mode reveals patterns.""" """ECB mode reveals patterns."""
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend()) cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor() encryptor = cipher.encryptor()
return encryptor.update(data) + encryptor.finalize() return encryptor.update(data) + encryptor.finalize()
def encrypt_cbc_random_iv(key: bytes, data: bytes) -> Tuple[bytes, bytes]: def encrypt_cbc_random_iv(key: bytes, data: bytes) -> Tuple[bytes, bytes]:
"""FP: CBC with random IV is secure.""" """CBC with random IV is secure."""
iv = os.urandom(16) iv = os.urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor() encryptor = cipher.encryptor()
@@ -94,7 +84,7 @@ def encrypt_cbc_random_iv(key: bytes, data: bytes) -> Tuple[bytes, bytes]:
def create_insecure_context() -> ssl.SSLContext: def create_insecure_context() -> ssl.SSLContext:
"""TP: Certificate verification disabled.""" """Certificate verification disabled."""
context = ssl.create_default_context() context = ssl.create_default_context()
context.check_hostname = False context.check_hostname = False
context.verify_mode = ssl.CERT_NONE context.verify_mode = ssl.CERT_NONE
@@ -102,7 +92,7 @@ def create_insecure_context() -> ssl.SSLContext:
def create_secure_context() -> ssl.SSLContext: def create_secure_context() -> ssl.SSLContext:
"""FP: Properly configured secure context.""" """Properly configured secure context."""
context = ssl.create_default_context() context = ssl.create_default_context()
context.check_hostname = True context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED context.verify_mode = ssl.CERT_REQUIRED

View File

@@ -1,10 +1,4 @@
"""Database module - streamlined version. """Database module - streamlined version."""
FINDING CLASSIFICATIONS:
- TRUE POSITIVE (TP): Actual security vulnerability
- FALSE POSITIVE (FP): Flagged but not a real issue in context
- UNCERTAIN: Could be either depending on deployment context
"""
import hashlib import hashlib
import hmac import hmac
@@ -27,21 +21,21 @@ class DatabaseManager:
# ========================================================================= # =========================================================================
def find_by_username_unsafe(self, username: str) -> Optional[dict]: def find_by_username_unsafe(self, username: str) -> Optional[dict]:
"""TP: SQL injection via string formatting.""" """SQL injection via string formatting."""
session = self.Session() session = self.Session()
query = f"SELECT * FROM users WHERE username = '{username}'" query = f"SELECT * FROM users WHERE username = '{username}'"
result = session.execute(text(query)) result = session.execute(text(query))
return result.fetchone() return result.fetchone()
def search_users_unsafe(self, search_term: str) -> List[dict]: def search_users_unsafe(self, search_term: str) -> List[dict]:
"""TP: SQL injection in LIKE clause.""" """SQL injection in LIKE clause."""
session = self.Session() session = self.Session()
query = f"SELECT * FROM users WHERE username LIKE '%{search_term}%'" query = f"SELECT * FROM users WHERE username LIKE '%{search_term}%'"
result = session.execute(text(query)) result = session.execute(text(query))
return result.fetchall() return result.fetchall()
def find_by_id_safe(self, user_id: int) -> Optional[dict]: def find_by_id_safe(self, user_id: int) -> Optional[dict]:
"""FP: Parameterized query is safe.""" """Parameterized query is safe."""
session = self.Session() session = self.Session()
result = session.execute( result = session.execute(
text("SELECT * FROM users WHERE id = :id"), {"id": user_id} text("SELECT * FROM users WHERE id = :id"), {"id": user_id}
@@ -49,7 +43,7 @@ class DatabaseManager:
return result.fetchone() return result.fetchone()
def dynamic_column_sort(self, column: str, order: str = "ASC") -> List[dict]: def dynamic_column_sort(self, column: str, order: str = "ASC") -> List[dict]:
"""UNCERTAIN: Column name from allowlist but still uses f-string.""" """Column name from allowlist but still uses f-string."""
allowed_columns = ["username", "email", "created_at"] allowed_columns = ["username", "email", "created_at"]
if column not in allowed_columns: if column not in allowed_columns:
raise ValueError("Invalid column") raise ValueError("Invalid column")
@@ -63,15 +57,15 @@ class PasswordManager:
"""Password hashing patterns.""" """Password hashing patterns."""
def hash_password_md5(self, password: str) -> str: def hash_password_md5(self, password: str) -> str:
"""TP: MD5 is cryptographically broken for passwords.""" """MD5 is cryptographically broken for passwords."""
return hashlib.md5(password.encode()).hexdigest() return hashlib.md5(password.encode()).hexdigest()
def hash_password_sha1(self, password: str) -> str: def hash_password_sha1(self, password: str) -> str:
"""TP: SHA1 is weak for password hashing.""" """SHA1 is weak for password hashing."""
return hashlib.sha1(password.encode()).hexdigest() return hashlib.sha1(password.encode()).hexdigest()
def compute_file_checksum_md5(self, filepath: str) -> str: def compute_file_checksum_md5(self, filepath: str) -> str:
"""FP: MD5 acceptable for file integrity (non-security).""" """MD5 acceptable for file integrity (non-security)."""
hasher = hashlib.md5(usedforsecurity=False) hasher = hashlib.md5(usedforsecurity=False)
with open(filepath, "rb") as f: with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""): for chunk in iter(lambda: f.read(4096), b""):
@@ -81,12 +75,12 @@ class PasswordManager:
def verify_signature_sha256( def verify_signature_sha256(
self, message: bytes, signature: str, key: bytes self, message: bytes, signature: str, key: bytes
) -> bool: ) -> bool:
"""FP: HMAC-SHA256 for signatures is secure.""" """HMAC-SHA256 for signatures is secure."""
expected = hmac.new(key, message, hashlib.sha256).hexdigest() expected = hmac.new(key, message, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature) return hmac.compare_digest(expected, signature)
def hash_password_pbkdf2(self, password: str) -> tuple: def hash_password_pbkdf2(self, password: str) -> tuple:
"""FP: PBKDF2 is a proper password hash.""" """PBKDF2 is a proper password hash."""
salt = secrets.token_bytes(32) salt = secrets.token_bytes(32)
key = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 600000) key = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 600000)
return key.hex(), salt.hex() return key.hex(), salt.hex()

View File

@@ -1,10 +1,4 @@
"""Network client module - streamlined version. """Network client module - streamlined version."""
FINDING CLASSIFICATIONS:
- TRUE POSITIVE (TP): Actual security vulnerability
- FALSE POSITIVE (FP): Flagged but not a real issue in context
- UNCERTAIN: Could be either depending on deployment context
"""
import ssl import ssl
import urllib.request import urllib.request
@@ -21,25 +15,25 @@ class APIClient:
self.base_url = base_url self.base_url = base_url
def get_insecure(self, endpoint: str) -> Dict: def get_insecure(self, endpoint: str) -> Dict:
"""TP: SSL verification disabled.""" """SSL verification disabled."""
url = urljoin(self.base_url, endpoint) url = urljoin(self.base_url, endpoint)
response = requests.get(url, verify=False, timeout=30) response = requests.get(url, verify=False, timeout=30)
return response.json() return response.json()
def get_secure(self, endpoint: str) -> Dict: def get_secure(self, endpoint: str) -> Dict:
"""FP: Default SSL verification.""" """Default SSL verification."""
url = urljoin(self.base_url, endpoint) url = urljoin(self.base_url, endpoint)
response = requests.get(url, verify=True, timeout=30) response = requests.get(url, verify=True, timeout=30)
return response.json() return response.json()
def get_no_timeout(self, endpoint: str) -> Dict: def get_no_timeout(self, endpoint: str) -> Dict:
"""TP: No timeout specified.""" """No timeout specified."""
url = urljoin(self.base_url, endpoint) url = urljoin(self.base_url, endpoint)
response = requests.get(url) # No timeout! response = requests.get(url) # No timeout!
return response.json() return response.json()
def get_with_timeout(self, endpoint: str) -> Dict: def get_with_timeout(self, endpoint: str) -> Dict:
"""FP: Proper timeout specified.""" """Proper timeout specified."""
url = urljoin(self.base_url, endpoint) url = urljoin(self.base_url, endpoint)
response = requests.get(url, timeout=30) response = requests.get(url, timeout=30)
return response.json() return response.json()
@@ -49,12 +43,12 @@ class URLFetcher:
"""Fetch URLs.""" """Fetch URLs."""
def fetch_any_url(self, url: str) -> bytes: def fetch_any_url(self, url: str) -> bytes:
"""TP: Arbitrary URL fetch (SSRF potential).""" """Arbitrary URL fetch (SSRF potential)."""
with urllib.request.urlopen(url) as response: with urllib.request.urlopen(url) as response:
return response.read() return response.read()
def fetch_https_only(self, url: str) -> bytes: def fetch_https_only(self, url: str) -> bytes:
"""FP: Only HTTPS URLs allowed.""" """Only HTTPS URLs allowed."""
parsed = urlparse(url) parsed = urlparse(url)
if parsed.scheme != "https": if parsed.scheme != "https":
raise ValueError("Only HTTPS URLs allowed") raise ValueError("Only HTTPS URLs allowed")
@@ -62,7 +56,7 @@ class URLFetcher:
return response.read() return response.read()
def fetch_allowlisted(self, url: str) -> bytes: def fetch_allowlisted(self, url: str) -> bytes:
"""FP: Domain allowlist.""" """Domain allowlist."""
allowed = ["api.example.com", "cdn.example.com"] allowed = ["api.example.com", "cdn.example.com"]
parsed = urlparse(url) parsed = urlparse(url)
if parsed.netloc not in allowed: if parsed.netloc not in allowed:
@@ -71,7 +65,7 @@ class URLFetcher:
return response.read() return response.read()
def fetch_unverified_ssl(self, url: str) -> bytes: def fetch_unverified_ssl(self, url: str) -> bytes:
"""TP: Unverified SSL context.""" """Unverified SSL context."""
context = ssl._create_unverified_context() context = ssl._create_unverified_context()
with urllib.request.urlopen(url, context=context) as response: with urllib.request.urlopen(url, context=context) as response:
return response.read() return response.read()

View File

@@ -1,19 +1,12 @@
"""Production secrets - THIS FILE SHOULD NOT BE IN VERSION CONTROL! """Production secrets - THIS FILE SHOULD NOT BE IN VERSION CONTROL!"""
TP: All secrets in this file are real production credentials.
"""
# TP: Real AWS credentials
AWS_PROD_ACCESS_KEY = "AKIAI44QH8DHBPRODKEY" AWS_PROD_ACCESS_KEY = "AKIAI44QH8DHBPRODKEY"
AWS_PROD_SECRET_KEY = "je7MtGbClwBF/2Zp9Utk/h3yCo8nvbPRODSECRET" AWS_PROD_SECRET_KEY = "je7MtGbClwBF/2Zp9Utk/h3yCo8nvbPRODSECRET"
# TP: Real Stripe production key
STRIPE_PROD_SECRET = "sk_live_51HqJK2eZvKYlo2CProdSecretKey123" STRIPE_PROD_SECRET = "sk_live_51HqJK2eZvKYlo2CProdSecretKey123"
# TP: Real GitHub PAT
GITHUB_PROD_PAT = "ghp_ProdTokenaBcDeFgHiJkLmNoPqRsTuVwXyZ12" GITHUB_PROD_PAT = "ghp_ProdTokenaBcDeFgHiJkLmNoPqRsTuVwXyZ12"
# TP: Real SSH private key
SSH_PRIVATE_KEY = """-----BEGIN OPENSSH PRIVATE KEY----- SSH_PRIVATE_KEY = """-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEA0Z3VS5JJcds3xfn/ygWyF8PbnGy0AHB1x4JLHlLxMIWPqlrRkj17 NhAAAAAwEAAQAAAYEA0Z3VS5JJcds3xfn/ygWyF8PbnGy0AHB1x4JLHlLxMIWPqlrRkj17

View File

@@ -1,10 +1,4 @@
"""Semgrep-specific patterns module - streamlined version. """Semgrep-specific patterns module - streamlined version."""
FINDING CLASSIFICATIONS:
- TRUE POSITIVE (TP): Actual security vulnerability
- FALSE POSITIVE (FP): Flagged but not a real issue in context
- UNCERTAIN: Could be either depending on deployment context
"""
import os import os
import re import re
@@ -28,14 +22,14 @@ app = Flask(__name__)
@app.route("/redirect/unsafe") @app.route("/redirect/unsafe")
def redirect_unsafe(): def redirect_unsafe():
"""TP: Open redirect - user controls destination URL.""" """Open redirect - user controls destination URL."""
next_url = request.args.get("next", "/") next_url = request.args.get("next", "/")
return redirect(next_url) return redirect(next_url)
@app.route("/redirect/validated") @app.route("/redirect/validated")
def redirect_validated(): def redirect_validated():
"""FP: Redirect with domain validation.""" """Redirect with domain validation."""
next_url = request.args.get("next", "/") next_url = request.args.get("next", "/")
parsed = urlparse(next_url) parsed = urlparse(next_url)
if parsed.netloc and parsed.netloc != "example.com": if parsed.netloc and parsed.netloc != "example.com":
@@ -45,7 +39,7 @@ def redirect_validated():
@app.route("/redirect/relative_only") @app.route("/redirect/relative_only")
def redirect_relative(): def redirect_relative():
"""UNCERTAIN: Checks :// but not protocol-relative URLs.""" """Checks :// but not protocol-relative URLs."""
next_url = request.args.get("next", "/") next_url = request.args.get("next", "/")
if "://" in next_url: if "://" in next_url:
return redirect("/") return redirect("/")
@@ -59,7 +53,7 @@ def redirect_relative():
@app.route("/files/download") @app.route("/files/download")
def download_file(): def download_file():
"""TP: Path traversal via user-controlled filename.""" """Path traversal via user-controlled filename."""
filename = request.args.get("file", "readme.txt") filename = request.args.get("file", "readme.txt")
filepath = os.path.join("/var/www/files", filename) filepath = os.path.join("/var/www/files", filename)
return send_file(filepath) return send_file(filepath)
@@ -67,7 +61,7 @@ def download_file():
@app.route("/files/safe_download") @app.route("/files/safe_download")
def safe_download(): def safe_download():
"""FP: Path traversal prevented with realpath check.""" """Path traversal prevented with realpath check."""
filename = request.args.get("file", "readme.txt") filename = request.args.get("file", "readme.txt")
base_dir = "/var/www/files" base_dir = "/var/www/files"
filepath = os.path.join(base_dir, filename) filepath = os.path.join(base_dir, filename)
@@ -82,16 +76,16 @@ def safe_download():
# ============================================================================= # =============================================================================
JWT_SECRET = "super_secret_jwt_key_12345" # TP: Hardcoded JWT secret JWT_SECRET = "super_secret_jwt_key_12345"
def verify_jwt_none_allowed(token: str) -> Dict: def verify_jwt_none_allowed(token: str) -> Dict:
"""TP: JWT verification disabled.""" """JWT verification disabled."""
return jwt.decode(token, options={"verify_signature": False}) return jwt.decode(token, options={"verify_signature": False})
def verify_jwt_secure(token: str, secret: str) -> Dict: def verify_jwt_secure(token: str, secret: str) -> Dict:
"""FP: JWT with externally provided secret.""" """JWT with externally provided secret."""
return jwt.decode(token, secret, algorithms=["HS256"]) return jwt.decode(token, secret, algorithms=["HS256"])
@@ -102,7 +96,7 @@ def verify_jwt_secure(token: str, secret: str) -> Dict:
@app.route("/fetch/url") @app.route("/fetch/url")
def fetch_url(): def fetch_url():
"""TP: SSRF - fetches arbitrary user-provided URL.""" """SSRF - fetches arbitrary user-provided URL."""
url = request.args.get("url") url = request.args.get("url")
response = requests.get(url) response = requests.get(url)
return response.text return response.text
@@ -110,7 +104,7 @@ def fetch_url():
@app.route("/fetch/allowlisted") @app.route("/fetch/allowlisted")
def fetch_allowlisted(): def fetch_allowlisted():
"""FP: SSRF prevented with domain allowlist.""" """SSRF prevented with domain allowlist."""
url = request.args.get("url") url = request.args.get("url")
parsed = urlparse(url) parsed = urlparse(url)
allowed_hosts = ["api.github.com", "cdn.example.com"] allowed_hosts = ["api.github.com", "cdn.example.com"]
@@ -125,15 +119,12 @@ def fetch_allowlisted():
# ============================================================================= # =============================================================================
# TP: Hardcoded credentials
DATABASE_URL = "postgresql://admin:secretpassword123@db.example.com:5432/prod" DATABASE_URL = "postgresql://admin:secretpassword123@db.example.com:5432/prod"
AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE" AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
# FP: Placeholder credentials
EXAMPLE_API_KEY = "your_api_key_here" EXAMPLE_API_KEY = "your_api_key_here"
TEST_DATABASE_URL = "postgresql://test:test@localhost:5432/test_db" TEST_DATABASE_URL = "postgresql://test:test@localhost:5432/test_db"
# UNCERTAIN: Test key format but could be real
STRIPE_KEY = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" STRIPE_KEY = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
@@ -143,12 +134,12 @@ STRIPE_KEY = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
def run_system_command(user_input: str): def run_system_command(user_input: str):
"""TP: Command injection via os.system.""" """Command injection via os.system."""
os.system(f"echo {user_input}") os.system(f"echo {user_input}")
def run_safe_command(): def run_safe_command():
"""FP: Hardcoded command, no user input.""" """Hardcoded command, no user input."""
os.system("date") os.system("date")
@@ -160,12 +151,12 @@ import random
def generate_token_insecure() -> str: def generate_token_insecure() -> str:
"""TP: Using random module for security token.""" """Using random module for security token."""
return "".join(random.choices("abcdefghijklmnopqrstuvwxyz0123456789", k=32)) return "".join(random.choices("abcdefghijklmnopqrstuvwxyz0123456789", k=32))
def shuffle_playlist(items: List[str]) -> List[str]: def shuffle_playlist(items: List[str]) -> List[str]:
"""FP: Random for non-security purpose.""" """Random for non-security purpose."""
shuffled = items.copy() shuffled = items.copy()
random.shuffle(shuffled) random.shuffle(shuffled)
return shuffled return shuffled
@@ -176,12 +167,12 @@ def shuffle_playlist(items: List[str]) -> List[str]:
# ============================================================================= # =============================================================================
DEBUG_MODE = True # TP: Debug flag DEBUG_MODE = True
@app.route("/debug/eval") @app.route("/debug/eval")
def debug_eval(): def debug_eval():
"""TP: Debug endpoint with eval.""" """Debug endpoint with eval."""
if DEBUG_MODE: if DEBUG_MODE:
expr = request.args.get("expr", "1+1") expr = request.args.get("expr", "1+1")
return str(eval(expr)) return str(eval(expr))
@@ -189,4 +180,4 @@ def debug_eval():
if __name__ == "__main__": if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5001) # TP: Debug mode app.run(debug=True, host="0.0.0.0", port=5001)

View File

@@ -9,30 +9,28 @@ from typing import Optional
class AuthenticationService: class AuthenticationService:
"""Handle user authentication.""" """Handle user authentication."""
# TP: Hardcoded JWT secret
JWT_SECRET = "hardcoded_jwt_secret_key_2024" JWT_SECRET = "hardcoded_jwt_secret_key_2024"
# FP: Default for development only
DEV_SECRET = "development_only_not_production" DEV_SECRET = "development_only_not_production"
def hash_password_insecure(self, password: str) -> str: def hash_password_insecure(self, password: str) -> str:
"""TP: MD5 for password hashing.""" """MD5 for password hashing."""
return hashlib.md5(password.encode()).hexdigest() return hashlib.md5(password.encode()).hexdigest()
def generate_token_secure(self, user_id: int) -> str: def generate_token_secure(self, user_id: int) -> str:
"""FP: Secrets module for token generation.""" """Secrets module for token generation."""
token = secrets.token_urlsafe(32) token = secrets.token_urlsafe(32)
return f"{user_id}:{token}" return f"{user_id}:{token}"
def verify_webhook_signature(self, payload: bytes, signature: str) -> bool: def verify_webhook_signature(self, payload: bytes, signature: str) -> bool:
"""FP: HMAC verification is secure.""" """HMAC verification is secure."""
expected = hmac.new( expected = hmac.new(
self.JWT_SECRET.encode(), payload, hashlib.sha256 self.JWT_SECRET.encode(), payload, hashlib.sha256
).hexdigest() ).hexdigest()
return hmac.compare_digest(expected, signature) return hmac.compare_digest(expected, signature)
def verify_webhook_insecure(self, payload: bytes, signature: str) -> bool: def verify_webhook_insecure(self, payload: bytes, signature: str) -> bool:
"""TP: Using == for signature comparison (timing attack).""" """Using == for signature comparison (timing attack)."""
expected = hmac.new( expected = hmac.new(
self.JWT_SECRET.encode(), payload, hashlib.sha256 self.JWT_SECRET.encode(), payload, hashlib.sha256
).hexdigest() ).hexdigest()

View File

@@ -11,32 +11,32 @@ class FileService:
"""Handle file operations.""" """Handle file operations."""
def load_pickle_user_path(self, filepath: str) -> Any: def load_pickle_user_path(self, filepath: str) -> Any:
"""TP: Pickle from user-controlled path.""" """Pickle from user-controlled path."""
with open(filepath, "rb") as f: with open(filepath, "rb") as f:
return pickle.load(f) return pickle.load(f)
def load_pickle_fixed_path(self) -> Any: def load_pickle_fixed_path(self) -> Any:
"""FP: Pickle from known internal path.""" """Pickle from known internal path."""
with open("/etc/app/cache.pkl", "rb") as f: with open("/etc/app/cache.pkl", "rb") as f:
return pickle.load(f) return pickle.load(f)
def save_temp_insecure(self, data: bytes) -> str: def save_temp_insecure(self, data: bytes) -> str:
"""TP: Predictable temp file.""" """Predictable temp file."""
filepath = f"/tmp/data_{os.getpid()}.dat" filepath = f"/tmp/data_{os.getpid()}.dat"
with open(filepath, "wb") as f: with open(filepath, "wb") as f:
f.write(data) f.write(data)
return filepath return filepath
def save_temp_secure(self, data: bytes) -> str: def save_temp_secure(self, data: bytes) -> str:
"""FP: Secure temp file creation.""" """Secure temp file creation."""
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
f.write(data) f.write(data)
return f.name return f.name
def load_yaml_unsafe(self, yaml_string: str) -> Any: def load_yaml_unsafe(self, yaml_string: str) -> Any:
"""TP: Unsafe YAML loader.""" """Unsafe YAML loader."""
return yaml.load(yaml_string, Loader=yaml.Loader) return yaml.load(yaml_string, Loader=yaml.Loader)
def load_yaml_safe(self, yaml_string: str) -> Any: def load_yaml_safe(self, yaml_string: str) -> Any:
"""FP: SafeLoader is secure.""" """SafeLoader is secure."""
return yaml.safe_load(yaml_string) return yaml.safe_load(yaml_string)

View File

@@ -1,20 +1,12 @@
"""Utilities module - streamlined for Pylint patterns. """Utilities module - streamlined for Pylint patterns."""
FINDING CLASSIFICATIONS:
- TRUE POSITIVE (TP): Actual code quality issue
- FALSE POSITIVE (FP): Flagged but acceptable in context
- UNCERTAIN: Depends on coding standards/context
"""
import json import json
import logging import logging
from typing import Any, Dict, List from typing import Any, Dict, List
# TP: Module-level variable not UPPER_CASE
global_counter = 0 global_counter = 0
# FP: Constant follows convention
MAX_RETRIES = 3 MAX_RETRIES = 3
@@ -23,23 +15,23 @@ MAX_RETRIES = 3
# ============================================================================= # =============================================================================
def processData(items): # TP: not snake_case def processData(items):
"""Process items.""" """Process items."""
return [item * 2 for item in items] return [item * 2 for item in items]
def calculate_total(values): # FP: Proper snake_case def calculate_total(values):
"""Calculate total.""" """Calculate total."""
return sum(values) return sum(values)
class userManager: # TP: not PascalCase class userManager:
"""Manage users.""" """Manage users."""
pass pass
class UserRepository: # FP: Proper PascalCase class UserRepository:
"""User repository.""" """User repository."""
pass pass
@@ -51,12 +43,12 @@ class UserRepository: # FP: Proper PascalCase
def too_many_arguments(a, b, c, d, e, f, g, h, i, j, k): def too_many_arguments(a, b, c, d, e, f, g, h, i, j, k):
"""TP: Too many arguments.""" """Too many arguments."""
return sum([a, b, c, d, e, f, g, h, i, j, k]) return sum([a, b, c, d, e, f, g, h, i, j, k])
def reasonable_arguments(user_id: int, name: str, email: str) -> dict: def reasonable_arguments(user_id: int, name: str, email: str) -> dict:
"""FP: Reasonable number of arguments.""" """Reasonable number of arguments."""
return {"id": user_id, "name": name, "email": email} return {"id": user_id, "name": name, "email": email}
@@ -65,14 +57,14 @@ def reasonable_arguments(user_id: int, name: str, email: str) -> dict:
# ============================================================================= # =============================================================================
def mutable_default_list(items=[]): # TP: Mutable default def mutable_default_list(items=[]):
"""TP: Mutable default argument.""" """Mutable default argument."""
items.append(1) items.append(1)
return items return items
def safe_default_none(items=None): # FP: Safe None default def safe_default_none(items=None):
"""FP: Safe None default pattern.""" """Safe None default pattern."""
if items is None: if items is None:
items = [] items = []
return items return items
@@ -84,15 +76,15 @@ def safe_default_none(items=None): # FP: Safe None default
def bare_except_handler(data): def bare_except_handler(data):
"""TP: Bare except catches everything.""" """Bare except catches everything."""
try: try:
return json.loads(data) return json.loads(data)
except: # TP: bare except except:
return None return None
def specific_except_handler(data): def specific_except_handler(data):
"""FP: Specific exception handling.""" """Specific exception handling."""
try: try:
return json.loads(data) return json.loads(data)
except json.JSONDecodeError: except json.JSONDecodeError:
@@ -104,13 +96,13 @@ def specific_except_handler(data):
# ============================================================================= # =============================================================================
def shadow_builtins(list, dict): # TP: Shadows builtins def shadow_builtins(list, dict):
"""TP: Shadows multiple builtins.""" """Shadows multiple builtins."""
return len(list) + len(dict) return len(list) + len(dict)
def proper_naming(items: List[int], mapping: Dict) -> int: # FP def proper_naming(items: List[int], mapping: Dict) -> int:
"""FP: Descriptive names don't shadow.""" """Descriptive names don't shadow."""
return len(items) + len(mapping) return len(items) + len(mapping)
@@ -119,15 +111,15 @@ def proper_naming(items: List[int], mapping: Dict) -> int: # FP
# ============================================================================= # =============================================================================
def inconsistent_return(value): # TP: Implicit None def inconsistent_return(value):
"""TP: Some paths return None implicitly.""" """Some paths return None implicitly."""
if value > 0: if value > 0:
return value return value
# Implicit None return # Implicit None return
def all_paths_return(value): # FP def all_paths_return(value):
"""FP: All paths return explicitly.""" """All paths return explicitly."""
if value > 0: if value > 0:
return value return value
return 0 return 0
@@ -138,16 +130,16 @@ def all_paths_return(value): # FP
# ============================================================================= # =============================================================================
def range_len_antipattern(items): # TP: Should use enumerate def range_len_antipattern(items):
"""TP: Should use enumerate.""" """Should use enumerate."""
result = [] result = []
for i in range(len(items)): for i in range(len(items)):
result.append((i, items[i])) result.append((i, items[i]))
return result return result
def proper_enumerate(items): # FP def proper_enumerate(items):
"""FP: Proper enumerate usage.""" """Proper enumerate usage."""
return [(i, item) for i, item in enumerate(items)] return [(i, item) for i, item in enumerate(items)]
@@ -156,20 +148,20 @@ def proper_enumerate(items): # FP
# ============================================================================= # =============================================================================
def function_without_docstring(): # TP: Missing docstring def function_without_docstring():
pass pass
def function_with_docstring(): # FP def function_with_docstring():
"""This function has a docstring.""" """This function has a docstring."""
pass pass
class ClassWithoutDocstring: # TP class ClassWithoutDocstring:
pass pass
class ClassWithDocstring: # FP class ClassWithDocstring:
"""This class has a docstring.""" """This class has a docstring."""
pass pass

View File

@@ -1,10 +1,4 @@
"""Web application module - streamlined version. """Web application module - streamlined version."""
FINDING CLASSIFICATIONS:
- TRUE POSITIVE (TP): Actual security vulnerability
- FALSE POSITIVE (FP): Flagged but not a real issue in context
- UNCERTAIN: Could be either depending on deployment context
"""
import os import os
import subprocess import subprocess
@@ -18,10 +12,8 @@ import yaml
app = Flask(__name__) app = Flask(__name__)
# TP: Hardcoded secret key
app.config["SECRET_KEY"] = "production_secret_key_v2_xK9#mP2$" app.config["SECRET_KEY"] = "production_secret_key_v2_xK9#mP2$"
# FP: Environment variable with fallback
app.config["DEV_API_KEY"] = os.environ.get("API_KEY", "dev_placeholder_key") app.config["DEV_API_KEY"] = os.environ.get("API_KEY", "dev_placeholder_key")
@@ -32,7 +24,7 @@ app.config["DEV_API_KEY"] = os.environ.get("API_KEY", "dev_placeholder_key")
@app.route("/admin/execute") @app.route("/admin/execute")
def admin_execute(): def admin_execute():
"""TP: Direct shell injection from user input.""" """Direct shell injection from user input."""
command = request.args.get("cmd", "whoami") command = request.args.get("cmd", "whoami")
result = subprocess.call(command, shell=True) result = subprocess.call(command, shell=True)
return {"exit_code": result} return {"exit_code": result}
@@ -40,14 +32,14 @@ def admin_execute():
@app.route("/build/compile") @app.route("/build/compile")
def compile_code(): def compile_code():
"""FP: Shell=True but command is completely hardcoded.""" """Shell=True but command is completely hardcoded."""
result = subprocess.call("make clean && make build", shell=True) result = subprocess.call("make clean && make build", shell=True)
return {"status": "completed", "exit_code": result} return {"status": "completed", "exit_code": result}
@app.route("/health/disk") @app.route("/health/disk")
def check_disk(): def check_disk():
"""FP: No shell, hardcoded command list.""" """No shell, hardcoded command list."""
result = subprocess.run(["/usr/bin/df", "-h", "/"], capture_output=True, text=True) result = subprocess.run(["/usr/bin/df", "-h", "/"], capture_output=True, text=True)
return {"disk_usage": result.stdout} return {"disk_usage": result.stdout}
@@ -59,14 +51,14 @@ def check_disk():
@app.route("/render/custom") @app.route("/render/custom")
def render_custom(): def render_custom():
"""TP: User controls entire template string.""" """User controls entire template string."""
template = request.args.get("tpl", "{{ 7*7 }}") template = request.args.get("tpl", "{{ 7*7 }}")
return render_template_string(template) return render_template_string(template)
@app.route("/report/generate") @app.route("/report/generate")
def generate_report(): def generate_report():
"""FP: Template hardcoded, only data is dynamic.""" """Template hardcoded, only data is dynamic."""
user_name = request.args.get("name", "Anonymous") user_name = request.args.get("name", "Anonymous")
REPORT_TEMPLATE = "<h1>Report for {{ name }}</h1>" REPORT_TEMPLATE = "<h1>Report for {{ name }}</h1>"
return render_template_string(REPORT_TEMPLATE, name=user_name) return render_template_string(REPORT_TEMPLATE, name=user_name)
@@ -79,7 +71,7 @@ def generate_report():
@app.route("/session/load") @app.route("/session/load")
def load_session(): def load_session():
"""TP: Pickle load from user-controlled path.""" """Pickle load from user-controlled path."""
session_file = request.args.get("file") session_file = request.args.get("file")
with open(session_file, "rb") as f: with open(session_file, "rb") as f:
data = pickle.load(f) data = pickle.load(f)
@@ -88,7 +80,7 @@ def load_session():
@app.route("/config/load") @app.route("/config/load")
def load_config(): def load_config():
"""FP: Pickle from known safe internal path.""" """Pickle from known safe internal path."""
with open("/etc/app/internal_config.pkl", "rb") as f: with open("/etc/app/internal_config.pkl", "rb") as f:
config = pickle.load(f) config = pickle.load(f)
return {"config_keys": list(config.keys())} return {"config_keys": list(config.keys())}
@@ -101,7 +93,7 @@ def load_config():
@app.route("/yaml/parse") @app.route("/yaml/parse")
def parse_yaml(): def parse_yaml():
"""TP: Unsafe YAML loader with user input.""" """Unsafe YAML loader with user input."""
yaml_content = request.get_data(as_text=True) yaml_content = request.get_data(as_text=True)
data = yaml.load(yaml_content, Loader=yaml.Loader) data = yaml.load(yaml_content, Loader=yaml.Loader)
return {"parsed": data} return {"parsed": data}
@@ -109,7 +101,7 @@ def parse_yaml():
@app.route("/yaml/safe") @app.route("/yaml/safe")
def yaml_safe(): def yaml_safe():
"""FP: SafeLoader is secure.""" """SafeLoader is secure."""
yaml_content = request.get_data(as_text=True) yaml_content = request.get_data(as_text=True)
data = yaml.safe_load(yaml_content) data = yaml.safe_load(yaml_content)
return {"data": data} return {"data": data}
@@ -122,7 +114,7 @@ def yaml_safe():
@app.route("/upload/process") @app.route("/upload/process")
def process_upload(): def process_upload():
"""TP: Predictable temp file path.""" """Predictable temp file path."""
data = request.get_data() data = request.get_data()
filepath = f"/tmp/upload_{os.getpid()}" filepath = f"/tmp/upload_{os.getpid()}"
with open(filepath, "wb") as f: with open(filepath, "wb") as f:
@@ -132,7 +124,7 @@ def process_upload():
@app.route("/export/csv") @app.route("/export/csv")
def export_csv(): def export_csv():
"""FP: Uses tempfile module correctly.""" """Uses tempfile module correctly."""
with tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) as f: with tempfile.NamedTemporaryFile(mode="w", suffix=".csv", delete=False) as f:
f.write("name,value\n") f.write("name,value\n")
return {"file": f.name} return {"file": f.name}
@@ -144,12 +136,12 @@ def export_csv():
def eval_user_code(code: str) -> Any: def eval_user_code(code: str) -> Any:
"""TP: Direct eval of user input.""" """Direct eval of user input."""
return eval(code) return eval(code)
def literal_eval_safe(expr: str) -> Any: def literal_eval_safe(expr: str) -> Any:
"""FP: ast.literal_eval is safe.""" """ast.literal_eval is safe."""
import ast import ast
return ast.literal_eval(expr) return ast.literal_eval(expr)
@@ -161,12 +153,12 @@ def literal_eval_safe(expr: str) -> Any:
def get_production_bind() -> str: def get_production_bind() -> str:
"""TP: Binds to all interfaces.""" """Binds to all interfaces."""
return "0.0.0.0" return "0.0.0.0"
def get_internal_bind() -> str: def get_internal_bind() -> str:
"""FP: Localhost only.""" """Localhost only."""
return "127.0.0.1" return "127.0.0.1"

View File

@@ -1,19 +1,12 @@
"""Test fixtures containing mock credentials. """Test fixtures containing mock credentials."""
FP: All values are test fixtures, not real credentials.
"""
# FP: Example AWS credentials
TEST_AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE" TEST_AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
TEST_AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" TEST_AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
# FP: Mock Stripe keys (sk_test indicates test mode)
MOCK_STRIPE_SECRET = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" MOCK_STRIPE_SECRET = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
# FP: Example JWT for testing
MOCK_JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U" MOCK_JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U"
# FP: Test database URL (localhost)
TEST_DATABASE_URL = "postgresql://testuser:testpassword@localhost:5432/testdb" TEST_DATABASE_URL = "postgresql://testuser:testpassword@localhost:5432/testdb"
@@ -23,3 +16,11 @@ def get_test_credentials():
"username": "test_user", "username": "test_user",
"password": "test_password_123", "password": "test_password_123",
} }
class MockAuthProvider:
"""Mock authentication provider for testing."""
def get_token(self) -> str:
"""Return mock token."""
return "mock_access_token_xyz789"