code wiki / (root) / nx_message_spam_detector.nx

nx_message_spam_detector.nx source

↩ module page · 169 lines · 8758 B

1// nx_message_spam_detector.nx -- rate-limit + chat-spam + abuse-vector audit. 2// 3// module: nishi-core.perception.message_spam_detector 4// depends: nishi-core.perception.profile + nishi-core.perception.load_test_harness + 5// nishi-core.perception.perceptual_dataset + nishi-core.io.syscalls 6// disk_kb: 5 7// capability: PERCEPTION 8// wired_status: PARTIAL_WIRED 9// 10// MISSING_CAPABILITIES: 11// - WS_FRAME_SPRAY (issue N WebSocket text frames per second from 12// M virtual users to find rate-limit threshold) 13// - HTTP_POST_FLOOD (REST API spam vector) 14// - PAYLOAD_FUZZ (oversized / malformed / unicode-bomb frame variations) 15// - RATE_LIMIT_DETECTION (parse 429 responses + Retry-After headers + 16// ban-window observation) 17// - PER_IP_ISOLATION_TEST (does rate-limit apply per-IP or per-session 18// or per-account? test all three vectors) 19// - SHADOW_BAN_DETECTION (some servers silently drop spam without 429; 20// detect by sending probe + observing peer recv of probe) 21// 22// license_tier: PUBLIC_NISHI_SUBSTRATE 23// genealogy_id: feedback-substrate-does-heavy-lifting-user-is-partner-not-gate_2026 + 24// feedback-substrate-primitives-meta-not-one-off_2026 + 25// feedback-racing-crew-team-honesty-threat-aware + 26// nx_threat_model + 27// owasp_2023_rate_limit_testing + 28// feedback-no-false-ok-substrate-honesty-audit 29// 30// User directive 2026-05-20: "if it does message spam, all that bullshit." 31// 32// THIS primitive measures whether the substrate's chat / WS / API 33// endpoints behave correctly under hostile load: rate-limited? banned? 34// shadow-banned? collapses? Lets through XSS / unicode-bomb? 35// Composes with nx_threat_model -- which ThreatActor classes does the 36// substrate actually defend against, measured not asserted? 37// 38// Reuse set: 39// - nishifamily.com/video chat (PRIMARY) 40// - Future Nishi public APIs of any kind 41// - Dog toy companion-app API (when shipped) 42// - Conservation acoustic upload endpoint (could be flooded by 43// non-conservation traffic abusing free upload) 44// - Vet diagnostic image upload (HIPAA-relevant abuse vector) 45// - Beekeeping hive data ingest (farm-network DOS resistance) 46// - Every Nishi endpoint that takes user input 47 48import "nx_syscalls.nx" 49import "nx_perceptual_profile.nx" 50import "nx_load_test_harness.nx" 51import "nx_perceptual_dataset.nx" 52 53// ===== Abuse vector sealed enum =================================== 54 55const NX_SPAM_VECTOR_RAPID_REPEAT: i64 = 1 // identical msg N times/sec 56const NX_SPAM_VECTOR_VARIED_BURST: i64 = 2 // N unique msgs in burst 57const NX_SPAM_VECTOR_OVERSIZED_PAYLOAD: i64 = 3 // single message > limit 58const NX_SPAM_VECTOR_MALFORMED_UTF8: i64 = 4 // invalid encoding 59const NX_SPAM_VECTOR_UNICODE_ZALGO: i64 = 5 // combining-char overflow 60const NX_SPAM_VECTOR_XSS_INJECTION: i64 = 6 // <script> / event handlers 61const NX_SPAM_VECTOR_SQL_INJECTION: i64 = 7 // SQL metachars in chat 62const NX_SPAM_VECTOR_PATH_TRAVERSAL: i64 = 8 // ../../../etc/passwd 63const NX_SPAM_VECTOR_BINARY_FRAME: i64 = 9 // binary on text channel 64const NX_SPAM_VECTOR_FRAGMENTATION: i64 = 10 // many tiny WS frames 65const NX_SPAM_VECTOR_SLOWLORIS: i64 = 11 // hold connection open, 66 // never finish frame 67const NX_SPAM_VECTOR_DUPLICATE_LOGIN: i64 = 12 // same account from N 68 // sessions simultaneously 69 70func nx_spam_vector_name(v: i64) -> *u8 { 71 if v == NX_SPAM_VECTOR_RAPID_REPEAT { return "RAPID_REPEAT" } 72 if v == NX_SPAM_VECTOR_VARIED_BURST { return "VARIED_BURST" } 73 if v == NX_SPAM_VECTOR_OVERSIZED_PAYLOAD { return "OVERSIZED_PAYLOAD" } 74 if v == NX_SPAM_VECTOR_MALFORMED_UTF8 { return "MALFORMED_UTF8" } 75 if v == NX_SPAM_VECTOR_UNICODE_ZALGO { return "UNICODE_ZALGO" } 76 if v == NX_SPAM_VECTOR_XSS_INJECTION { return "XSS_INJECTION" } 77 if v == NX_SPAM_VECTOR_SQL_INJECTION { return "SQL_INJECTION" } 78 if v == NX_SPAM_VECTOR_PATH_TRAVERSAL { return "PATH_TRAVERSAL" } 79 if v == NX_SPAM_VECTOR_BINARY_FRAME { return "BINARY_FRAME" } 80 if v == NX_SPAM_VECTOR_FRAGMENTATION { return "FRAGMENTATION" } 81 if v == NX_SPAM_VECTOR_SLOWLORIS { return "SLOWLORIS" } 82 if v == NX_SPAM_VECTOR_DUPLICATE_LOGIN { return "DUPLICATE_LOGIN" } 83 return "UNKNOWN_VECTOR" 84} 85 86// ===== Server response sealed enum ================================ 87// 88// How did the endpoint handle the vector? 89 90const NX_SPAM_RESP_REJECTED_429: i64 = 1 // rate-limited (PROPER) 91const NX_SPAM_RESP_REJECTED_400: i64 = 2 // bad request (PROPER for malformed) 92const NX_SPAM_RESP_REJECTED_413: i64 = 3 // payload too large (PROPER) 93const NX_SPAM_RESP_REJECTED_SANITIZED: i64 = 4 // accepted but content escaped 94const NX_SPAM_RESP_ACCEPTED_PROPAGATED: i64 = 5 // PASSED to other peers (BAD if XSS etc) 95const NX_SPAM_RESP_SHADOW_BANNED: i64 = 6 // accepted but silently dropped 96 // (sender thinks delivered) 97const NX_SPAM_RESP_CONNECTION_DROPPED: i64 = 7 // server killed connection 98const NX_SPAM_RESP_SERVER_HUNG: i64 = 8 // no response (BAD; slowloris worked) 99const NX_SPAM_RESP_DEPENDENCY_MISSING: i64 = 9 // PARTIAL_WIRED default 100 101func nx_spam_resp_name(r: i64) -> *u8 { 102 if r == NX_SPAM_RESP_REJECTED_429 { return "REJECTED_429" } 103 if r == NX_SPAM_RESP_REJECTED_400 { return "REJECTED_400" } 104 if r == NX_SPAM_RESP_REJECTED_413 { return "REJECTED_413" } 105 if r == NX_SPAM_RESP_REJECTED_SANITIZED { return "REJECTED_SANITIZED" } 106 if r == NX_SPAM_RESP_ACCEPTED_PROPAGATED { return "ACCEPTED_PROPAGATED" } 107 if r == NX_SPAM_RESP_SHADOW_BANNED { return "SHADOW_BANNED" } 108 if r == NX_SPAM_RESP_CONNECTION_DROPPED { return "CONNECTION_DROPPED" } 109 if r == NX_SPAM_RESP_SERVER_HUNG { return "SERVER_HUNG" } 110 if r == NX_SPAM_RESP_DEPENDENCY_MISSING { return "DEPENDENCY_MISSING" } 111 return "UNKNOWN_RESP" 112} 113 114// ===== Per-vector test result ===================================== 115 116struct NxSpamTestResult { 117 vector_id: i64 // NX_SPAM_VECTOR_* 118 msgs_sent: i64 119 msgs_accepted_count: i64 120 msgs_rejected_429_count: i64 121 msgs_rejected_other_count: i64 122 msgs_propagated_to_peers_count: i64 // critical for XSS / abuse 123 msgs_shadow_banned_count: i64 124 time_to_first_rate_limit_ms: i64 // how fast did defense kick in 125 server_health_after: i64 // is endpoint still responding? 126 severity: i64 // INFO / NOTICE / WARNING / ERROR / CRITICAL 127 // (matches nx_diag_sev) 128 overall_response: i64 // dominant NX_SPAM_RESP_* 129} 130 131// ===== Top-level entry stubs ====================================== 132 133// nx_spam_test_endpoint -- run one vector against endpoint, return result. 134 135func nx_spam_test_endpoint(endpoint_url_ptr: *u8, endpoint_url_len: i64, 136 vector_id: i64, intensity: i64, 137 duration_seconds: i64, 138 result_out_ptr: *NxSpamTestResult) -> i64 { 139 if endpoint_url_len <= 0 { return NX_SPAM_RESP_DEPENDENCY_MISSING } 140 if vector_id < NX_SPAM_VECTOR_RAPID_REPEAT { return NX_SPAM_RESP_DEPENDENCY_MISSING } 141 if vector_id > NX_SPAM_VECTOR_DUPLICATE_LOGIN { return NX_SPAM_RESP_DEPENDENCY_MISSING } 142 if intensity <= 0 { return NX_SPAM_RESP_DEPENDENCY_MISSING } 143 if duration_seconds <= 0 { return NX_SPAM_RESP_DEPENDENCY_MISSING } 144 // PARTIAL_WIRED: vector dispatchers queued. 145 return NX_SPAM_RESP_DEPENDENCY_MISSING 146} 147 148// nx_spam_test_full_audit -- run ALL 12 vectors against endpoint; produce 149// a single combined severity verdict. Used as a CI gate before any 150// public deploy. 151 152func nx_spam_test_full_audit(endpoint_url_ptr: *u8, endpoint_url_len: i64, 153 max_severity_observed_out: *i64) -> i64 { 154 if endpoint_url_len <= 0 { return 0 } 155 return 0 156} 157 158// nx_spam_test_persist_to_dataset -- write the per-vector result history 159// into nx_perceptual_dataset for regression-tracking + threat-model audit. 160 161func nx_spam_test_persist_to_dataset(result_ptr: *NxSpamTestResult) -> i64 { 162 return 0 163} 164 165// nx_spam_test_get_last_response -- inspector. 166 167func nx_spam_test_get_last_response() -> i64 { 168 return NX_SPAM_RESP_DEPENDENCY_MISSING 169}