What happened
Follow-up to PR #694 (fixes #691). While exercising the stochastic channel panel with invalid boundary inputs against POST /api/compute on production (commit 0dfc0c1), I found two remaining gaps:
Gap 1: no upper bound on NumClusters / NumSubPaths (potential DoS)
#694 added type + math.isfinite guards for these two keys but no maximum. The frontend StochasticPanel.tsx clamps them to [1, 50], but the API boundary accepts any finite integer.
NumClusters |
Result |
| 100 |
502 (worker killed) |
| 1000 |
502 (worker killed) |
| 10000 |
502 (worker killed) |
| 99999999 |
500 Unable to allocate 14.9 GiB for an array with shape (99999998, 20) and data type float64 |
Each of these requests consumed a gthread worker for up to the gunicorn 600 s timeout. Same class of issue as #658 — session-gated but trivial for any authenticated user (or any integration that constructs a share link with a bad override).
Suggested fix: mirror the frontend cap in the validator, e.g. reject NumClusters > 50 and NumSubPaths > 20, or whatever the upstream 3GPP generator realistically supports.
Gap 2: float overrides (KF_mu, AS_A_mu, ES_A_mu, SC_lambda) accept NaN / Inf and crash with cryptic 500
PR #694 only validated NumClusters and NumSubPaths. Other numeric override keys the panel exposes (and any keys accepted by aegis.channel.generator) are unguarded. Because JSON.stringify(NaN) serializes to null, sending NaN / Infinity from JS lands as None in the Python overrides dict, where it later hits float(None):
AS_A_mu=NaN -> 500: float() argument must be a string or a real number, not 'NoneType'
ES_A_mu=NaN -> 500: (same)
AS_A_mu=inf -> 500: (same)
KF_mu=inf -> 500: (same)
SC_lambda=NaN -> 500: (same)
This is exactly the same bypass class as #691 — just for the float-valued overrides. The JS NaN→null→None path also means the math.isfinite check on NumClusters/NumSubPaths catches the TypeError side (isinstance(val, (int,float)) rejects None), but the floats never make it into _STOCHASTIC_NUMERIC_OVERRIDE_KEYS.
Suggested fix: extend _STOCHASTIC_NUMERIC_OVERRIDE_KEYS to cover the float parameters the panel sends (KF_mu, AS_A_mu, AS_A_sigma, ES_A_mu, ES_A_sigma, SC_lambda, DS_mu, DS_sigma, SF_sigma, XPR_mu, XPR_sigma, etc.), or — cleaner — validate every value in stochastic_overrides against bool/None/isfinite uniformly, rather than maintaining a hand-curated allowlist that has to keep chasing the QuaDRiGa .conf schema.
Steps to reproduce
Drive directly with a session cookie from the authenticated UI:
// Gap 1
fetch('/api/compute', {method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({
body:'thelonious', pose:[0,0,0,0,0,0], antenna_position:[1.8,0,4],
freq_hz:2.8e10, power_dbm:65, mode:'spatial',
stochastic:true, stochastic_preset:'3GPP_38.901_UMa_LOS',
stochastic_overrides:{NumClusters:99999999}, stochastic_seed:42,
})}).then(r => r.text()).then(console.log)
// -> 500 "Unable to allocate 14.9 GiB..."
// Gap 2
fetch('/api/compute', {method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({
body:'thelonious', pose:[0,0,0,0,0,0], antenna_position:[1.8,0,4],
freq_hz:2.8e10, power_dbm:65, mode:'spatial',
stochastic:true, stochastic_preset:'3GPP_38.901_UMa_LOS',
stochastic_overrides:{KF_mu:NaN}, stochastic_seed:42,
})}).then(r => r.text()).then(console.log)
// -> 500 "float() argument must be a string or a real number, not 'NoneType'"
Tested as healthy (should not regress)
Filed by QA agent · the qa-bot label triggers an autofix workflow.
What happened
Follow-up to PR #694 (fixes #691). While exercising the stochastic channel panel with invalid boundary inputs against
POST /api/computeon production (commit0dfc0c1), I found two remaining gaps:Gap 1: no upper bound on
NumClusters/NumSubPaths(potential DoS)#694 added type +
math.isfiniteguards for these two keys but no maximum. The frontendStochasticPanel.tsxclamps them to[1, 50], but the API boundary accepts any finite integer.NumClustersUnable to allocate 14.9 GiB for an array with shape (99999998, 20) and data type float64Each of these requests consumed a gthread worker for up to the gunicorn 600 s timeout. Same class of issue as #658 — session-gated but trivial for any authenticated user (or any integration that constructs a share link with a bad override).
Suggested fix: mirror the frontend cap in the validator, e.g. reject
NumClusters > 50andNumSubPaths > 20, or whatever the upstream 3GPP generator realistically supports.Gap 2: float overrides (KF_mu, AS_A_mu, ES_A_mu, SC_lambda) accept NaN / Inf and crash with cryptic 500
PR #694 only validated
NumClustersandNumSubPaths. Other numeric override keys the panel exposes (and any keys accepted byaegis.channel.generator) are unguarded. BecauseJSON.stringify(NaN)serializes tonull, sendingNaN/Infinityfrom JS lands asNonein the Python overrides dict, where it later hitsfloat(None):This is exactly the same bypass class as #691 — just for the float-valued overrides. The JS NaN→null→None path also means the
math.isfinitecheck on NumClusters/NumSubPaths catches theTypeErrorside (isinstance(val, (int,float))rejects None), but the floats never make it into_STOCHASTIC_NUMERIC_OVERRIDE_KEYS.Suggested fix: extend
_STOCHASTIC_NUMERIC_OVERRIDE_KEYSto cover the float parameters the panel sends (KF_mu, AS_A_mu, AS_A_sigma, ES_A_mu, ES_A_sigma, SC_lambda, DS_mu, DS_sigma, SF_sigma, XPR_mu, XPR_sigma, etc.), or — cleaner — validate every value instochastic_overridesagainstbool/None/isfiniteuniformly, rather than maintaining a hand-curated allowlist that has to keep chasing the QuaDRiGa .conf schema.Steps to reproduce
Drive directly with a session cookie from the authenticated UI:
Tested as healthy (should not regress)
NumClusters:0,-5→ 400NumClusters must be >= 1✓ (Reject zero NumClusters/NumSubPaths in channel generator #664)NumClusters:NaN/"12"→ 400must be a number✓ (Validate stochastic_overrides at /api/compute boundary #694)NumSubPaths:0→ 400 ✓ (Reject zero NumClusters/NumSubPaths in channel generator #664)stochastic_preset:"__INVALID__","../../etc/passwd"→ 400Unknown stochastic preset✓ (Whitelist stochastic preset names at API boundary #693)Filed by QA agent · the
qa-botlabel triggers an autofix workflow.