Build1 distinct publisher2 min readPublished
The goPhone value is escaped for SQL, then dropped into an exec() string that PHP runs through /bin/sh. Any active agent can trigger the logout call, and on a production box the injected command runs under sudo.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Follow any of these and your For You feed starts watching them — no settings page required.
security
Xiiaozet's LK100W lets an unauthenticated caller switch on its admin services1 distinct publisher
build
Six MariaDB versions, one real difference: the only reason to leave 10.6 is the July 2026 clock1 distinct publisher
security
Six bugs, one order of operations: Avada's zero-click chain is a same-day patch1 distinct publisher
build
Once the question needs a cube, you own the parser1 distinct publisher
PHP's exec() hands the string to /bin/sh -c, which parses it before anything else runs [13]. Whether the shell still sees a live $(...) when the string arrives determines whether the payload executes, and here it does.
mysqli_real_escape_string exists to neutralize SQL quoting: quotes, backslashes, the NUL byte [10]. Backtick, dollar, parentheses, pipe, ampersand and semicolon do not break a SQL literal, so it leaves them alone [10]. Against a shell, that escaping does nothing to the characters that matter.
Three files stand between the request and exec(). goAPI.php runs goPhone through $astDB->escape(). goLogoutUser.php passes the escaped value to check_sip_login() on line 54. goFunctions.php then concatenates it, as $exten, into the exec() string on line 460 [11]. The middle call is why the gap went unnoticed: check_sip_login() reads as a SIP-registration lookup, not a command runner, so nobody at that call site was watching for a command sink [12].
The exec() target is a Perl wrapper, invoked as /usr/share/goautodial/goautodialc.pl "sudo /usr/sbin/asterisk -rx \"sip show peer $exten\"" [18]. The substitution never waits for Perl. It expands at the outer /bin/sh -c, at the PHP layer, before the wrapper runs [13]. The proof is the wrapper's own call log, which recorded only sip show peer 8300 while the injected command had already executed [16].
GOautodial ships goAPIv2 to /var/www/html through its installer, and the API is reachable by anyone with an agent login [7]. It is an open-source, Asterisk-based dialer with a wide install base [6]. Santosh Kumar Puppala reported the flaw and ran the chain end to end against unmodified source at HEAD 640a31f on PHP 8.2 with Apache and MariaDB [5][14].
Ranked by verification strength, evidence, and original report placement.
In GOautodial's goAPIv2, the goPhone request parameter is escaped for SQL with mysqli_real_escape_string and then concatenated into an exec() command string; shell metacharacters survive the SQL escape, so a $(...) payload runs on the host.
mysqli_real_escape_string neutralizes SQL quoting (quotes, backslashes, NUL) and does nothing to shell metacharacters; backtick, dollar, parentheses, pipe, ampersand and semicolon pass through untouched.
PHP's exec() runs its argument through /bin/sh -c, so command substitution inside $exten is expanded by the shell at the PHP layer before the Perl helper is invoked.
The report attributes the recurrence of this bug class to its hiding behind a function whose name sounds like sanitization; the value is escaped, just for the wrong language.
Any authenticated low-privilege agent, a role with no legitimate shell access, gets arbitrary OS command execution on the server running the API.
The flaw is classified CWE-78 and carries a CVSS 3.1 base score of 8.8, rated High.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · September 2, 2026
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
One researcher, thoroughly shown
Everything traces to one place — Puppala's dev.to write-up — yet that account is unusually concrete: source-to-sink tracing across goAPI.php, goLogoutUser.php line 54 and goFunctions.php line 460, a run against unmodified source at HEAD 640a31f, and an id payload that wrote uid=33(www-data) while the wrapper's log still showed only 'sip show peer 8300'. What it lacks is any second pair of eyes.
Patch shipped, uptake unseen
The only hard traction signal is the fix itself — commit 0ab2584 on the goAPIv2 master branch. How widely GOautodial is actually installed is asserted ('widely deployed') but never numbered, and nothing tells us how many operators have pulled the patch or whether the flaw was ever exploited in the wild.
A step ahead of the proof
The 8.8 rating and the line that real-world 'blast radius is worse than the score implies' run slightly ahead of what was actually demonstrated. The lab proved execution as www-data; the jump to sudo-level privilege is reasoned from how production hosts are configured rather than shown, and no independent confirmation exists yet.
Finder, writer and CVE-seeker in one
The same person found the bug, documented it, and is chasing a CVE credit — and posted it under his own byline on dev.to. That is a legitimate disclosure, but it is also every reason to lead with the highest defensible severity, which tempers how the framing should be read even where the technique is sound.
Serious, not yet settled
One publisher, one author, no vendor comment, CVE still pending. The detail and internal consistency are enough to take the finding seriously; the total absence of an independent check is enough to hold off treating it as settled.