Responsible Disclosure
74 Confirmed Bugs
Security and logic bugs found by Nightjar in popular Python packages. All 74 reproduced by direct execution. Verified 2026-03-29.
JWT expiry check skipped when exp=None (falsy check)
JWT expiry bypassed when exp=0 (Unix epoch is falsy)
fnmatch OAuth redirect URI allows query-param injection and fake-port attacks
OAuthProxyProvider(allowed_client_redirect_uris=None) allows ALL redirect URIs
create_budget mutable default created_at=time.time() frozen at import
jwt.decode(algorithms=None) skips algorithm allowlist entirely
Complete incompatibility with bcrypt 4.x/5.x — bcrypt.hash() broken
Infinite loop in split_text_into_chunks when overlap >= chunk_size
Full Python tracebacks returned in HTTP error responses
Hardcoded SECRET_KEY='mirofish-secret-key' and DEBUG=True defaults
Path traversal via platform query parameter
Path traversal via unvalidated simulation_id parameter
Duplicate close() method silently discards WAL checkpoint
fuzzy_find_and_replace with replace_all=True corrupts unrelated code
asyncio.Lock() at module level causes cross-thread deadlock
Middleware safety net skips recovery when commit_and_open_pr tool fails
git checkout -B force-resets existing branch on agent retry
Handoff conversation history markers allow developer-role trust escalation
ENS normalize_name() silently maps 62 fullwidth Unicode chars to ASCII — phishing vector
Sandbox fully bypassed when caller provides __import__ + getattr — confirmed RCE
9+ metric functions return np.nan as score sentinel — silently poisons aggregations
unquote("") raises IndexError on empty string
decimal_encoder(Decimal("sNaN")) raises ValueError
compress_schema mutates input dict in-place despite immutable design claim
getattr(dict, "ended") always returns time.time() — dict key ignored
X-Forwarded-For multi-hop format fails exact-match IP allowlist
Empty string accepted as HMAC secret key without warning
pbkdf2_sha256.hash("") succeeds — no minimum password length
URLSafeSerializer("") accepted — empty string creates HMAC-less tokens
3-byte HMAC key accepted — enforce_minimum_key_length defaults to False
OctKey.import_key(b"short") — 5-byte key accepted without warning for HS256
JWTClaims.validate() skips iss and aud validation by default
train() crashes with ValueError when vocab_size exceeds mergeable pairs
load() crashes when special token name contains a space
model_validator(mode='before') raises raw TypeError on bad input (not ValidationError)
model_copy() is shallow by default — mutating copy mutates original
model_copy(update=) bypasses all validators
required=True option allows empty string and whitespace-only values
Non-ASCII (CJK) characters pass isalnum() filter unchanged
_suggest_similar_files char-set heuristic returns semantically unrelated files
choose_cheap_model_route misses inflected keyword forms
_UPLOAD_SENTENCE_RE word boundary \b prevents /mnt/ path matching
_UPLOAD_SENTENCE_RE leaves garbled text when filename contains periods
str_replace_tool returns OK for empty files without checking old_str
UploadsMiddleware discards non-text content blocks in multi-modal messages
extract_repo_from_text returns repo name with embedded slash
GitHub URL with .git suffix produces invalid repo name
truncate_string violates length contract when max_length < 3
Forward-slash .git paths not filtered on Windows (os.sep='\\' splits on backslash)
add_conditional_edges() silently drops routing when no path_map and node is unregistered
_filter_sensitive_data_from_string leaks suffix when secrets share a prefix
_parse_function_tool_json_input returns non-dict for valid JSON scalars
InMemorySessionService silently overwrites existing session via whitespace-padded ID
resolve_source_to_stream() reads arbitrary OS paths — no base-directory guard
HKDF.derive(length=0) returns empty bytes instead of raising ValueError
Fernet.decrypt(ttl=0) accepts same-second tokens — off-by-one in TTL check
log_metric() silently stores NaN, inf, and -inf without raising
set_chord_size(0) stored silently — chord body fires immediately with no results
compile_restricted() returns code object for dangerous patterns — no SyntaxError raised
Tool description field: no sanitization — prompt injection payloads preserved verbatim in wire JSON
Parameter description fields: injection payloads preserved in inputSchema.properties
DataCompyScore raises ZeroDivisionError when both precision and recall are zero
AnswerAccuracy.average_scores silently returns NaN when both sub-scores are NaN
Background analytics thread POSTs telemetry on every score() call — opt-out only
factuality/parser.py raises ZeroDivisionError when LLM returns empty claims list
jwt.decode(None) raises AttributeError instead of JWTError
loads(token, max_age=0) does NOT expire tokens
null JSON input silently invokes tool with all default argument values
BashToolPolicy prefix validation bypassable via shell metacharacters
order_by() lacks explicit field-name whitelist guard analogous to aggregate patch
_execute_single_listener exceptions swallowed by asyncio.gather — non-deterministic flow state
validate_and_warn_tool_name return value ignored — invalid names register without error