Security News

Cybersecurity news aggregator

🔓
HIGH Vulnerabilities Reddit r/netsec

OpenSIPS SQL Injection to Authentication Bypass (CVE-2026-25554)

A high-severity SQL injection vulnerability (CVE-2026-25554, CVSS 6.5) in the auth_jwt module of OpenSIPS allows remote attackers to bypass SIP authentication and impersonate arbitrary users. The vulnerability affects OpenSIPS versions 3.1 and later that include the auth_jwt module, prior to the patch implemented in upstream PR #3807 in February 2026.
Read Full Article →

OpenSIPS SQL Injection to Full Authentication Bypass (CVE-2026-25554) Author Joshua Rogers Date Published March 19, 2026 The AISLE analyzer discovered a high-severity vulnerability in OpenSIPS , one of the most widely deployed open-source components in telecom and VoIP infrastructure. OpenSIPS helps providers route calls, register users, and enforce authentication across large-scale voice networks, which means weaknesses in this layer can have direct consequences for service security and trust. The issue, assigned CVE-2026-25554 with a severity score of 8.3, allowed SQL injection in a code path used for authentication. In practice, this meant a remote attacker could exploit the flaw to impersonate arbitrary SIP users without needing prior access to the environment. In affected deployments, that allowed an attacker to register as another subscriber, place calls under a trusted identity, or access services protected by SIP authentication. The vulnerability affects all OpenSIPS versions 3.1 and later that ship with the auth_jwt module, prior to the patch accepted upstream in PR #3807 in February. In the sections that follow, we explain how the issue works, and how it was fixed following responsible disclosure with the OpenSIPS maintainers. OpenSIPS: The Basics OpenSIPS is an open-source SIP (Session Initiation Protocol) server used heavily in VoIP and real-time communication infrastructure. If you've made a VoIP call, there's a reasonable chance an OpenSIPS instance was involved. When you dial someone via VoIP, SIP locates the other party and negotiates the session. It also handles the entire state machine of a call, ranging from ringing to holds to hanging up. (Note that SIP only handles signaling, and voice data travels over RTP (Real-time Transport Protocol), which is a separate path.) As an open source SIP proxy/server, OpenSIPS enables enterprise-grade throughput with millions of simultaneous calls. For that reason, it is widely used by carriers and providers around the world. How SIP authentication works When a SIP client such as a phone, softphone, or gateway places a call, it sends a SIP request (such as REGISTER or INVITE) to a SIP proxy (like OpenSIPS). The proxy needs to verify the client's identity before it routes anything. Traditionally, SIP clients authenticate via HTTP Digest, in which the server presents clients with a nonce and clients respond by deriving a hash from their user credentials. However, this approach doesn’t compose well with modern identity systems for a number of reasons (it can’t delegate to external identity providers, and it doesn’t support token-based SSO). OpenSIPS’s auth_jwt module avoids this issue with JWT-based authentication, in which clients construct and sign a JWT (JSON Web Token) using a pre-shared HMAC secret.The JWT includes a tag claim that specifies which cryptographic key OpenSIPS must use during signature validation (it essentially acts as a key selector). Once it receives the token, the server: Reads the tag claim to determine which key profile to look up; Queries the database for the corresponding signing secret; Verifies the JWT signature against the secret. The vulnerability breaks step 2 of this process. The Vulnerability The vulnerable function, jwt_db_authorize() , lives in modules/auth_jwt/authorize.c . The function starts by decoding the JWT to obtain the tag claim: C 1 if ( jwt_decode ( & jwt , jwt_token_buf , NULL , 0 ) != 0 || jwt == NULL ) { 2 LM_ERR ( "Failed to decode jwt \n" ) ; 3 goto err_out ; 4 } 5 6 tag_s = ( char * ) jwt_get_grant ( jwt , ( const char * ) jwt_tag_claim . s ) ; Copy The NULL, 0 parameters mean "decode but don't verify" (in libjwt, passing NULL/0 for the key parameters skips signature verification), so at this point, tag_s contains whatever string the sender put in the tag claim. That is, it’s raw, attacker-controlled input. Next, tag_s is inserted directly into a raw SQL query using snprintf : C 1 tag . s = tag_s ; 2 tag . len = strlen ( tag_s ) ; 3 4 /* ... */ 5 6 n = snprintf ( p , len , 7 " from %.*s a inner join %.*s b on a.%.*s = b.%.*s" 8 " where a.%.*s='%.*s'" 9 " and %ld >= b.%.*s and %ld < b.%.s" , 10 profiles_table . len , profiles_table . s , 11 secrets_table . len , secrets_table . s , 12 tag_column . len , tag_column . s , 13 secret_tag_column . len , secret_tag_column . s , 14 tag_column . len , tag_column . s , 15 tag . len , tag . s , / < -- attacker - controlled , unescaped * / 16 unix_ts , start_ts_column . len , start_ts_column . s , 17 unix_ts , end_ts_column . len , end_ts_column . s ) ; Copy Note that the tag value is placed directly inside the single-quoted SQL string '%.*s' with no escaping. In other words, this is a textbook case of SQL injection. Attack Overview Here’s what the query this function builds looks like: JavaScript 1 SELECT a . sip_username , b . secret 2 FROM jwt_profiles a 3 INNER JOIN jwt_secrets b ON a . tag = b . corresponding_tag 4 WHERE a . tag = '<ATTACKER_INPUT>' 5 AND < unix...

Share this article