{"id":"CVE-2026-96634","kind":"vulnerability","aliases":["CVE-2026-96634","GHSA-p96f-p2p2-2g3h"],"related":[],"title":"AdminNeo SQLite: multi_query Incorrect Check of Function Return Value RCE","description":"### Summary\n\nThis vulnerability is a patch bypass that exploits catastrophic backtracking in a regular expression used to filter ATTACH statements in AdminNeo's SQLite functionality. The original vulnerability (CVE-2021-43008) allowed authenticated users to create PHP files through SQLite ATTACH statements, achieving remote code execution. The patch introduced a regex filter to block ATTACH queries, but this filter is vulnerable to catastrophic backtracking.\n\nOriginally reported by @zdi-disclosures in Adminer: https://github.com/vrana/adminer/security/advisories/GHSA-3582-q6xq-5vf7\n\n### Analysis\n\n**[Source]** sql.inc.php :: SQL import handler:47\n\n```php\n$query = get_file(\"sql_file\", true, \";\");\n```\n\n> User uploads a malicious SQL file through the import form. The file content is read into the `$query` variable without any initial sanitization.\n\n**[Transform]** sql.inc.php :: SQL import handler:87\n\n```php\n// Query parsing loop that extracts individual SQL statements\n```\n\n> The uploaded SQL content is processed in a loop that splits it into individual queries. Each query `$query` is extracted for processing.\n\n**[Context]** sql.inc.php :: SQL import handler:65\n\n```php\n$space = \"(?:\\\\s|/\\\\*[\\s\\S]*?\\\\*/|(?:#|$line_comment)[^\\n]*\\n?|--\\r?\\n)\";\n```\n\n> Definition of the `$space` regex pattern used in the ATTACH filter. The possessive quantifier `*+` combined with SQLite comment patterns (`--`) creates the catastrophic backtracking vulnerability when many comment lines are processed.\n\n**[Transform]** sql.inc.php :: SQL import handler:146\n\n```php\nif (DIALECT == \"sqlite\" && preg_match(\"~^$space*+ATTACH\\\\b~i\", $q, $match)) {\n```\n\n> The ATTACH query filter check. When the regex encounters 350,000 SQLite comment lines (`--`), it triggers catastrophic backtracking. The possessive quantifier `*+` causes exponential backtracking, eventually hitting PHP's backtracking limit and causing `preg_match()` to return `false` instead of `0` or `1`, bypassing the security filter.\n\n**[Sink]** sql.inc.php :: SQL import handler:162\n\n```php\nConnection::get()->multiQuery($q)\n```\n\n> When the ATTACH filter is bypassed due to the `preg_match()` returning `false`, the malicious SQL query containing the ATTACH statement is executed. This allows the attacker to create a `.php` file with embedded PHP code, achieving remote code execution when the file is accessed via HTTP.\n\nThe root cause is that PHP's `preg_match()` function returns `false` when the backtracking limit is exceeded, but the code only checks for truthy values (1 for match), treating `false` the same as `0` (no match). This allows the ATTACH statement to bypass the security filter.\n\n-- CREDIT ---------------------------------------\nThis vulnerability was discovered by:\n0daystolive (Sorcery Ltd) working with TrendAI Zero Day Initiative\n\nZero Day Initiative\nzdi-disclosures@trendmicro.com\n\nThe PGP key used for all ZDI vendor communications is available from:\nhttp://www.zerodayinitiative.com/documents/disclosures-pgp-key.asc\n\n-- INFORMATION ABOUT THE ZDI --------------------\nEstablished by TippingPoint and acquired by Trend Micro, the Zero Day Initiative (ZDI) neither re-sells vulnerability details nor exploit code. Instead, upon notifying the affected product vendor, the ZDI provides its Trend Micro TippingPoint customers with zero day protection through its intrusion prevention technology. Explicit details regarding the specifics of the vulnerability are not exposed to any parties until an official vendor patch is publicly available.\n\nPlease contact us for further details or refer to:\n\nhttp://www.zerodayinitiative.com\n\n-- DISCLOSURE POLICY ----------------------------\nOur vulnerability disclosure policy is available online at:\nhttp://www.zerodayinitiative.com/advisories/disclosure_policy/","summary":"AdminNeo's SQLite SQL import filter blocks ATTACH statements using a regular expression that can be made to exhaust PHP's backtracking limit, causing preg_match to return false and the check to pass. An authenticated user can then create a PHP file through ATTACH and reach remote code execution over HTTP.","severity":"medium","cvss":null,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"adminneo-org/adminneo","fixed":["5.5.1"],"affected":"< 5.5.1","ecosystem":"composer"}],"ecosystems":["composer"],"tags":["adminneo","cwe-74","package","php","self-hosted","sqlite"],"not_affected_if":["auth-required","managed-hosting","non-sqlite-driver"],"how_to_check":"- Check the AdminNeo version in `composer show adminneo-org/adminneo` and see whether it is below `5.5.1`\n- Confirm whether the SQLite driver and the SQL import feature are enabled in your AdminNeo deployment","fix":"- `adminneo-org/adminneo` move to `5.5.1` or later","status":"open","published_at":"2026-10-30T22:53:08+00:00","first_seen_at":"2026-10-30T22:56:53+00:00","triaged_at":"2026-10-30T22:58:44+00:00","updated_at":"2026-10-30T22:58:44+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-10-30T22:58:44Z","model":"claude-haiku-5-5","output":{"fix":"- `adminneo-org/adminneo` move to `5.5.1` or later","reach":"internet","title":"AdminNeo SQLite import: regex backtracking lets SQL bypass filter, run PHP","impact":"high","summary":"AdminNeo's SQLite SQL import filter blocks ATTACH statements using a regular expression that can be made to exhaust PHP's backtracking limit, causing preg_match to return false and the check to pass. An authenticated user can then create a PHP file through ATTACH and reach remote code execution over HTTP.","audience":"developers","category":"package","nicknames":[],"who_cares":["adminneo","php","sqlite","self-hosted"],"confidence":0.8,"fix_status":"available","needs_auth":"yes","worst_case":"authenticated user runs PHP code on the server","analyst_note":"Confirm the affected SQLite driver and import feature conditions against the maintainer advisory at https://github.com/advisories/GHSA-p96f-p2p2-2g3h.","how_to_check":"- Check the AdminNeo version in `composer show adminneo-org/adminneo` and see whether it is below `5.5.1`\n- Confirm whether the SQLite driver and the SQL import feature are enabled in your AdminNeo deployment","plain_action":"","needs_analyst":true,"not_affected_if":["auth-required","non-sqlite-driver","managed-hosting"],"who_is_affected":"AdminNeo installations that use the SQLite driver and expose the SQL import form to users with login access. Deployments that use only MySQL or PostgreSQL, or that do not expose the import form, are not reached through this path.","user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000858,"input_tokens":5563,"output_tokens":604,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-2021':117C '-2026':13A,21A '-43008':118C '-74':29B '-96634':14A,22A '/adminneo':26A '/advisories/disclosure_policy/':581C '/documents/disclosures-pgp-key.asc':486C '/vrana/adminer/security/advisories/ghsa-3582-q6xq-5vf7':162C '0':341C,440C '000':312C '0daystolive':459C '1':343C,432C '146':289C '162':353C '2g3h':19A '350':311C '47':169C '65':242C '87':205C 'access':403C 'achiev':130C,395C 'acquir':495C 'admin':159C 'adminneo':1A,24A,27B,36B,109C 'adminneo-org':23A 'affect':517C 'allow':119C,383C,444C 'analysi':163C 'attach':43B,80B,106C,128C,142C,263C,297C,303C,361C,378C,446C 'attack':385C 'authent':71B,120C 'avail':482C,558C,576C 'b':298C 'backtrack':57B,98C,151C,276C,319C,325C,330C,420C 'block':42B,141C 'bypass':94C,344C,364C,449C 'catastroph':97C,150C,275C,318C 'caus':59B,323C,333C,408C 'check':6A,67B,306C,428C 'code':84B,132C,394C,397C,426C,512C 'combin':268C 'comment':249C,271C,280C,314C 'communic':480C 'connect':355C 'contact':560C 'contain':376C 'content':189C,218C 'context':237C 'creat':75B,123C,273C,387C 'credit':453C 'custom':527C 'cve':12A,20A,116C 'cwe':28B 'day':466C,469C,501C,530C 'definit':254C 'detail':509C,538C,564C 'dialect':292C 'disclosur':157C,569C,573C 'discov':457C 'due':365C 'embed':392C 'encount':310C 'establish':491C 'eventu':326C 'exceed':423C 'execut':85B,133C,381C,398C 'exhaust':54B 'explicit':537C 'exploit':96C,511C 'exponenti':324C 'expos':547C 'express':48B,102C 'extract':211C,234C 'fals':64B,338C,371C,417C,436C 'file':78B,125C,173C,175C,182C,188C,390C,401C 'filter':41B,105C,139C,146C,264C,305C,347C,362C,452C 'form':186C 'function':8A,112C,415C 'get':172C,356C 'ghsa':16A 'ghsa-p96f-p2p2-2g3h':15A 'github.com':161C 'github.com/vrana/adminer/security/advisories/ghsa-3582-q6xq-5vf7':160C 'handler':168C,204C,241C,288C,352C 'hit':327C 'host':34B 'http':87B,405C 'import':40B,167C,185C,203C,240C,287C,351C 'incorrect':5A 'individu':212C,228C 'inform':487C 'initi':198C,467C,470C,502C 'instead':339C,513C 'introduc':136C 'intrus':534C 'key':474C 'limit':58B,331C,421C 'line':248C,281C,315C 'loop':209C,223C 'ltd':461C 'made':52B 'malici':180C,373C 'mani':279C 'match':61B,295C,301C,335C,369C,414C,434C,442C 'micro':498C,525C 'multi':3A 'multiqueri':357C 'n':250C,251C,253C 'neither':504C 'notifi':515C 'offici':553C 'onlin':577C 'org':25A 'origin':114C,152C 'p2p2':18A 'p96f':17A 'packag':30B 'pars':208C 'parti':550C 'pass':69B 'patch':93C,135C,555C 'pattern':259C,272C 'pgp':473C 'php':31B,55B,77B,124C,170C,206C,243C,290C,328C,354C,389C,393C,411C 'pleas':559C 'polici':570C,574C 'possess':266C,321C 'preg':60B,294C,334C,368C,413C 'prevent':535C 'process':220C,236C,283C 'product':518C 'protect':531C 'provid':522C 'public':557C 'q':300C,358C 'quantifi':267C,322C 'queri':4A,143C,171C,194C,207C,229C,231C,232C,304C,375C 'r':252C 'rce':11A 're':506C 're-sel':505C 'reach':82B 'read':191C 'refer':566C 'regard':539C 'regex':138C,258C,309C 'regular':47B,101C 'remot':83B,131C,396C 'report':153C 'return':9A,63B,337C,370C,416C 'root':407C 'sanit':199C 'secur':346C,451C 'self':33B 'self-host':32B 'sell':507C 'sink':348C 'sorceri':460C 'sourc':164C 'space':244C,257C,296C 'specif':541C 'split':225C 'sql':39B,166C,174C,181C,202C,213C,217C,239C,286C,350C,374C 'sql.inc.php':165C,201C,238C,285C,349C 'sqlite':2A,35B,38B,111C,127C,270C,293C,313C 'statement':44B,107C,129C,214C,379C,447C 'summari':88C 'technolog':536C 'tippingpoint':493C,526C 'transform':200C,284C 'treat':435C 'trend':497C,524C 'trendai':464C 'trigger':317C 'true':176C 'truthi':430C 'upload':178C,216C 'upon':514C 'us':561C 'use':45B,103C,260C,475C 'user':72B,121C,177C 'valu':10A,431C 'variabl':195C 'vendor':479C,519C,554C 'via':404C 'vulner':90C,115C,148C,277C,455C,508C,544C,572C 'without':196C 'work':462C 'www.zerodayinitiative.com':485C,568C,580C 'www.zerodayinitiative.com/advisories/disclosure_policy/':579C 'www.zerodayinitiative.com/documents/disclosures-pgp-key.asc':484C 'zdi':156C,478C,490C,503C,521C 'zdi-disclosur':155C 'zdi-disclosures@trendmicro.com':471C 'zero':465C,468C,500C,529C '~i':299C","nicknames":[],"mitigations":[],"who_affected":"AdminNeo installations that use the SQLite driver and expose the SQL import form to users with login access. Deployments that use only MySQL or PostgreSQL, or that do not expose the import form, are not reached through this path.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"first_public_at":"2026-10-30T22:53:08+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-p96f-p2p2-2g3h","url":"https://github.com/advisories/GHSA-p96f-p2p2-2g3h","severity":"medium","published_at":"2026-10-30T22:53:08+00:00","modified_at":"2026-10-30T22:53:11+00:00","first_seen_at":"2026-10-30T22:56:53+00:00","fetched_at":"2026-10-30T22:56:53+00:00","note":null}],"documents":[{"id":26525,"url":"https://api.github.com/repos/adminneo-org/adminneo/security-advisories/GHSA-p96f-p2p2-2g3h","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":26526,"url":"https://github.com/adminneo-org/adminneo/security/advisories/GHSA-p96f-p2p2-2g3h","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":26527,"url":"https://github.com/adminneo-org/adminneo/commit/7e5658ffb0d890cd1a6152a09e3172da85ca4b77","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":26394,"url":"https://github.com/adminneo-org/adminneo/releases/tag/v5.5.1","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release: github.com"}],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}