Bugfix Issue 1736 ReqSpecEdit Unrenderable Action - sebiboga/testlink-upgraded GitHub Wiki
Bugfix: #1736 — legacy reqSpecEdit.php refuses unrenderable doAction with a 302 and no Event Viewer noise
Problem
The legacy Requirement Specification editor lib/requirements/reqSpecEdit.php logged 3 E_WARNING
rows and answered a 28-byte Can not process RENDERING!!! body for any doAction that was not a
reqSpecCommands method. Worse, internal helper methods of reqSpecCommands were being invoked via
method_exists() with the wrong argument count or visibility, producing silent HTTP 500 with
0 bytes and 0 log rows. An array-shaped ?doAction[]=x triggered an uncaught TypeError in the
shared input layer, also producing a silent 500.
Root cause
- Dispatch used
method_exists($commandMgr,$pFn)as a whitelist (24 method_exists-visible members, only 18 GUI actions). The matched method was called with a fixed 2-argument signature regardless of its arity/visibility. inputparameter.class.php:295callstrim()unconditionally onSTRING_Nvalues; a non-scalar$_REQUEST['doAction']causestrim(array)→TypeErrorbefore the controller runs.
Fix
All changes in lib/requirements/reqSpecEdit.php:
reqSpecEditDropShapedAction()unsets a non-scalar$_REQUEST['doAction']beforeR_PARAMS().reqSpecEditActionWhitelist()returns the exact 18-case list ofrenderGui()'s GUI-rendering switch and is consulted withis_string($pFn) && $pFn !== '' && isset(...)(only whitelisted names are invoked).reqSpecEditRefuseUnknownAction()logs onetLog(..., 'INFO')row with a fixed literal message (attacker-controlled value is deliberately NOT interpolated) and 302s togui/templates/requirements/reqSpecMgmt.htmlwithtproject_idcarried forward. INFO does not persist below WARNING, so crafted URLs cannot write Error/Warning rows.renderGui()'sdefault:branch null-guards$opObjas defence in depth.
Evidence
Pre-fix (unknown doAction=init)
- HTTP 200, 28 bytes, body
Can not process RENDERING!!! - 3 new
eventsrows (alllog_level=2, line 147)
Post-fix (unknown doAction=init)
- HTTP 302 →
http://localhost:8082/gui/templates/requirements/reqSpecMgmt.html?tproject_id=<TP> - 0 new
eventsrows
Pre-fix (internal helper ?doAction=simpleCompare)
- HTTP 500, 0 bytes, 0 new
eventsrows
Post-fix (internal helper ?doAction=simpleCompare)
- HTTP 302, 0 new
eventsrows
Unchanged (real form)
?doAction=create&parentID=<id>→ HTTP 200, real form renders (15646 bytes)?doAction=edit&req_spec_id=<id>→ HTTP 200, real form renders (15981 bytes)
Regression
32/32 cases PASS. The whitelist ⇄ renderGui() switch invariant is enforced (18 == 18), and every
doAction targeted at reqSpecEdit.php in-repo is whitelisted. Browser verification confirms the
302 lands on the Requirements Specification Management screen with project context intact, while
the create form still renders fully.
Notes
The shared trim(array) defect remains in inputparameter.class.php:295 (#1738). Two pre-existing
warnings in reqSpecCommands.class.php (deleteFile() missing $argsObj->uploadOp, bulkReqMon()
foreach(null) on empty specs) are #1737. The last two method_exists() dispatches (reqEdit.php:41,
planMilestonesEdit.php:30) are #1739. None were fixed here (measured identical pre-fix).