XPath Injection in Smolagents search_item_ctrl_f
A helper function in Hugging Face's Smolagents library builds web page search queries by directly inserting text into a query template, without sanitizing it. If untrusted text reaches this function, an attacker can break out of the intended search and alter what the underlying automated browser does.
How the attack works
The vulnerable function search_item_ctrl_f() builds an XPath locator by pasting search text straight into a fixed template: //*[contains(text(), '<TEXT>')]. If the text contains a single quote, that quote closes the string early, and anything after it - operators like or, and, |, or bracket expressions - becomes live XPath logic instead of literal search text. This altered locator is then sent as a real Selenium/WebDriver command (either over HTTP to chromedriver/geckodriver/Grid, or as a subprocess call from generated code), so the injected structure actually executes against the live page. The rule catches this by looking for both the tell-tale template shape and an operator character sitting right after a broken-out quote, together with evidence that a WebDriver session or Selenium code actually ran.
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- 7f3c9d21-4b8e-4a15-9c62-8d5f1e2a6b40
- Severity
- High
Why it matters
An attacker who controls the search text can redirect a browser-automation agent's page queries to select different elements than intended - potentially exposing hidden data, clicking unintended controls, or otherwise steering the agent's browser actions away from the user's request.
What you can do
- →Do not pass untrusted or user-supplied text directly into search_item_ctrl_f() or any XPath template built by string concatenation.
- →Sanitize or escape single quotes in search text before it reaches XPath-building code, or switch to parameterized/quote-safe locator construction.
- →Review any agent workflows where an LLM or external source supplies search terms used in browser automation, and add validation on that input.
- →Be aware this detection only covers XPath queries sent through WebDriver (HTTP or subprocess); queries applied in-process to already-fetched HTML via lxml/BeautifulSoup are not visible to this or any current detection and need separate code review.
Known benign look-alikes
- A genuine page-text search whose term contains an apostrophe immediately followed by an XPath keyword or operator - e.g. searching for "it' and that", "rock 'n' roll/blues", "O'Brien | Ltd". This produces a structurally identical malformed locator with no malicious intent. The bounded [^']{0,300} span plus the requirement that an operator (not a letter) sit directly after the closing quote keeps ordinary apostrophes such as "don't", "boys'" and "O'Brien" from matching, but it cannot separate an unlucky search string from a crafted one - hence action report.
- Hand-written Selenium locators that legitimately extend the same shape, e.g. //*[contains(text(), 'Next') and @role='button'] or a union //*[contains(text(), 'Next')]|//button[@id='next']. These are not produced by search_item_ctrl_f but share the "//*[contains(text(), '" prefix. The //* wildcard prefix requirement makes this uncommon (hand-written selectors usually name a tag) but it is the main residual FP class.
- CI runs of the smolagents test suite or a security regression test that asserts on the unsanitised locator - suppressed by filter_test_code.
- Security documentation, advisories, cheat sheets and pentest reports that transit an HTTP request while quoting an XPath injection payload - suppressed by filter_reference_material.
- An agent sending a Selenium snippet to a model API for review or repair, where the payload rides in a chat completion body rather than a WebDriver command - suppressed by filter_llm_api_payload.