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}