SQL Injection in Photo Share Website Signup
CVE-2026-19211 exposes a critical SQL injection flaw in SourceCodester Photo Share Website 1.0's signup endpoint, enabling remote data exfiltration.
Overview
CVE-2026-19211 is a classic SQL injection vulnerability residing in the user registration workflow of SourceCodester Photo Share Website 1.0, a PHP-based social photo-sharing platform distributed freely on SourceCodester. The flaw exists in the email parameter passed to /social/ajax.php?action=signup, where user-supplied input is interpolated directly into a SQL query without sanitization or parameterization. Because the endpoint is publicly reachable and requires no prior authentication, any remote attacker can trivially trigger the condition.
Security researchers identified the vulnerability and published a proof-of-concept, which is now publicly available. The disclosure follows responsible patterns consistent with VulnDB submission, and the exploit has been confirmed reproducible against the unpatched 1.0 release. SourceCodester applications are widely deployed by students, small businesses, and hobbyist developers who often run them on shared hosting without additional web-application firewall protections, making the attack surface broader than the project’s niche audience might suggest.
The CVSS 3.x base score of 7.3 (High) reflects the low attack complexity, no required privileges, no user interaction, and the partial confidentiality, integrity, and availability impact achievable through the injection. Organizations running this software — or derivatives of it — should treat remediation as urgent.
Technical Analysis
The root cause is unsanitized concatenation of the HTTP POST parameter email directly into a SQL INSERT or SELECT statement inside ajax.php. The following snippet represents the vulnerable pattern as it would realistically appear in the codebase:
// /social/ajax.php (action=signup — VULNERABLE)
if ($_POST['action'] === 'signup') {
$email = $_POST['email']; // raw user input, no sanitization
$username = $_POST['username'];
$password = md5($_POST['password']); // weak hashing, separate issue
// Unsanitized variable interpolated directly into the query string
$query = "SELECT * FROM users WHERE email = '$email'";
$result = mysqli_query($conn, $query);
if (mysqli_num_rows($result) === 0) {
$insert = "INSERT INTO users (username, email, password)
VALUES ('$username', '$email', '$password')";
mysqli_query($conn, $insert);
echo json_encode(['status' => 'success']);
} else {
echo json_encode(['status' => 'exists']);
}
}
The mechanism is straightforward: the application reads $_POST['email'] and places it verbatim into both the duplicate-check SELECT and the subsequent INSERT query. Because neither mysqli_real_escape_string() nor prepared statements are used, an attacker can inject arbitrary SQL by supplying a payload such as:
[email protected]' OR '1'='1
or, for blind boolean-based extraction:
[email protected]' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE id=1)='a'-- -
A time-based payload is equally viable:
[email protected]' AND SLEEP(5)-- -
Because the INSERT path also uses the unescaped variable, a second-order injection vector exists: malicious data stored during registration can be re-executed later when the application reads and re-queries the stored email, compounding the risk beyond the initial signup request. The use of md5() for password hashing is a secondary weakness — hashes extracted via this injection are trivially reversible with precomputed rainbow tables — but that is outside the immediate scope of this CVE.
Impact
An unauthenticated remote attacker exploiting CVE-2026-19211 can:
- Extract the full database schema and contents, including user credentials, personal information, session tokens, and any private photos or metadata stored in the application’s database.
- Bypass authentication by manipulating the duplicate-check query to return controlled result sets, potentially facilitating account takeover without knowing a valid password.
- Write files to disk if the MySQL
FILEprivilege is granted to the application’s database user, enabling web shell deployment and full server compromise. - Enumerate backend infrastructure through error messages or timing differences, leaking database version, hostname, and directory paths.
The CVSS vector AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L accurately captures the network-accessible, zero-privilege nature of the attack alongside high confidentiality impact. In shared-hosting environments common among SourceCodester deployments, a compromised database account may expose data belonging to other co-hosted applications on the same MySQL instance.
How to Fix It
The definitive fix requires replacing string concatenation with parameterized prepared statements using MySQLi or PDO. No amount of input filtering is an adequate substitute for query parameterization.
// /social/ajax.php (action=signup — FIXED)
if ($_POST['action'] === 'signup') {
$email = trim($_POST['email']);
$username = trim($_POST['username']);
$password = password_hash($_POST['password'], PASSWORD_BCRYPT); // use bcrypt
// Parameterized duplicate check
$stmt = $conn->prepare("SELECT id FROM users WHERE email = ?");
$stmt->bind_param("s", $email);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows === 0) {
$stmt->close();
// Parameterized insert
$insert = $conn->prepare(
"INSERT INTO users (username, email, password) VALUES (?, ?, ?)"
);
$insert->bind_param("sss", $username, $email, $password);
$insert->execute();
$insert->close();
echo json_encode(['status' => 'success']);
} else {
$stmt->close();
echo json_encode(['status' => 'exists']);
}
}
Additional hardening steps:
- Validate input format: Use
filter_var($email, FILTER_VALIDATE_EMAIL)before the database query to reject structurally invalid addresses early. - Principle of least privilege: The application’s MySQL user should have only
SELECT,INSERT,UPDATE, andDELETEon the application’s own database — neverFILE,SUPER, or global grants. - Replace MD5 with bcrypt/Argon2: The
password_hash()/password_verify()API has been available since PHP 5.5 and provides adaptive, salted hashing. - Enable a WAF rule: At the infrastructure layer, deploy rules blocking common SQL injection patterns as a defence-in-depth measure, not as a primary control.
- Upgrade or replace: SourceCodester scripts are not actively maintained with security patch releases. Organizations using this codebase in production should audit every query in the codebase, not only the signup endpoint.
Our Take
SQL injection through unsanitized POST parameters in PHP applications is one of the oldest vulnerability classes in web security, and yet it persists with striking regularity in freely distributed CRUD applications. The reason is structural: tutorial-grade PHP code written to demonstrate functionality rarely models secure-by-default patterns, and developers who download and deploy these scripts inherit all their technical debt along with the feature set.
For enterprise security teams, this CVE is a reminder that supply-chain risk is not limited to npm packages and Maven artifacts. PHP scripts downloaded from code-sharing repositories and integrated into internal tools or customer-facing portals carry the same exposure. DAST coverage of registration and authentication endpoints — where user-controlled input first enters the application — is non-negotiable. A single unauthenticated injection in a signup form is sufficient to compromise an entire user database.
The broader lesson: injection vulnerabilities are a training problem as much as a tooling problem. Developers writing raw SQL in PHP today are doing so because the codebase they inherited did it, or because the tutorial they followed did not cover parameterization. Security culture that normalizes code review for injection patterns at pull-request time will catch these far earlier than any post-deployment scan.
Detection with SAST
Static analysis tools detect this vulnerability class under CWE-89: Improper Neutralization of Special Elements used in an SQL Command. Offensive360’s SAST engine flags this pattern by tracing taint flow from HTTP superglobals ($_POST, $_GET, $_REQUEST, $_COOKIE) through string concatenation or interpolation operations that terminate in a database query execution function (mysqli_query, mysql_query, PDO::query, pg_query, etc.).
Key detection rules applied to this CVE:
- Source identification:
$_POST['email']is classified as an untrusted, user-controlled source. - Sanitizer absence check: No call to
mysqli_real_escape_string(),addslashes(), or equivalent is detected in the data flow between source and sink (though neither is an acceptable long-term fix). - Sink identification:
mysqli_query($conn, $query)where$querycontains a tainted variable is the injection sink. - Prepared-statement check: The absence of
$conn->prepare()/bind_param()orPDO::prepare()/bindValue()in the code path confirms the vulnerability.
SAST analysis of the second-order vector requires inter-procedural taint tracking: data stored to the database in one code path must be tracked as a tainted source when it is subsequently read and re-used in another query. Offensive360’s engine performs cross-function taint propagation to surface exactly these second-order injection patterns that simpler line-by-line scanners miss.
References
Detect this vulnerability class in your codebase
Offensive360 SAST scans your source code for CVE-2026-19211-class vulnerabilities and thousands of other patterns — across 60+ languages.