Bind XPath variables in Nokogiri instead of string interpolation
When you look up XML nodes by attribute value in Nokogiri, it’s tempting to interpolate the value straight into the XPath:
doc.at_xpath("//item[@id='#{id}']")
That works when id is predictable. It’s shakier when the value comes from a
user upload, an API payload, or anything else you don’t control. A value like
foo" or @id="bar can break out of the string literal and match a different
node than you meant. Same idea as SQL injection, just with XPath.
I ran into this parsing a DOCX file, looking up a w:styleId in
word/styles.xml. Same fix regardless of where the XML came from.
I didn’t know Nokogiri could bind variables into XPath, but it can!
Pass the value as a keyword argument and reference it in the query with
$variable_name:
doc.at_xpath("//item[@id=$id]", id:)
With a namespace map, as you often need for Word documents:
doc.at_xpath("//w:style[@w:styleId=$style_id]", W, style_id:)
The crafted example is now treated as a literal string. Nothing matches, so you
get nil back instead of the wrong node.
This works with xpath, at_xpath, and anything else that accepts a bindings
hash as the last argument. Worth remembering whenever you’re building XPath
from external input. DOCX is just a ZIP full of untrusted XML, after all.