Jan 19, 2026·5 min read·65 visits
LaRecipe < 2.8.1 tries to 'fix' relative anchor links by prepending the current request URI. Unfortunately, it uses the full URI including the query string. By appending a Blade template payload (e.g., `?{{system('id')}}`) to the URL, an attacker can trick the server into rendering and executing malicious code. CVSS 10.0. Update immediately.
A critical Server-Side Template Injection (SSTI) vulnerability in the LaRecipe documentation package allows unauthenticated attackers to execute arbitrary code via simple query string manipulation.
We often treat documentation as a static, boring artifact—a collection of markdown files that developers write reluctantly and users read even more reluctantly. But in the modern Laravel ecosystem, documentation tools like LaRecipe are dynamic applications in their own right. They parse Markdown, highlight code, and—crucially—render Blade templates. That last part is where things get spicy.
LaRecipe is designed to make writing documentation easy. It takes your standard markdown files and wraps them in a beautiful UI. To do this, it processes the text, handles routing, and renders the output. It's a classic case of "complexity is the enemy of security."
In CVE-2025-53833, we aren't looking at a complex buffer overflow or a race condition that requires perfect timing. We are looking at a logic error so simple, so face-palmingly obvious in hindsight, that it reminds us why sanitizing input is the golden rule of web security. The vulnerability allows an unauthenticated attacker to turn a harmless documentation page into a remote shell with a single GET request.
The road to RCE is paved with good intentions. In this case, the developer wanted to solve a common annoyance: broken anchor links. When you write markdown, you often use relative links like [Setup](#setup) to jump to a specific section on the page. However, depending on how the routing is set up, these relative links might not behave as expected if the base URL isn't clear.
To fix this, LaRecipe implemented a replaceLinks method in src/Models/Documentation.php. The logic was straightforward: find any relative link starting with # and prepend the current page's URL to make it absolute. This ensures that clicking #setup actually takes the browser to http://site.com/docs/1.0#setup.
The fatal flaw was in how the application determined the "current page's URL." The code grabbed the entire request URI—path, parameters, and all—and blindly concatenated it into the HTML content before passing it to the template engine. This is the equivalent of taking a stranger's handwriting, photocopying it onto a check, and handing it to the bank teller without looking at what was written.
Let's look at the vulnerable code in src/Models/Documentation.php. The method replaceLinks takes the raw content and performs a string replacement. Here is the offending line:
// Vulnerable Code
public static function replaceLinks($version, $content)
{
// ...
// The application grabs the FULL URI, including query strings.
$content = str_replace('"#', '"'.request()->getRequestUri().'#', $content);
// ...
return $content;
}The function request()->getRequestUri() returns the complete URI. If I visit /docs/1.0?foo=bar, the function returns /docs/1.0?foo=bar. If the markdown content contains <a href="#section">, the code transforms it into:
<a href="/docs/1.0?foo=bar#section">
Because this content is subsequently rendered by Laravel's Blade engine, any Blade syntax injected into that query string gets executed. The fix was embarrassingly simple: swap getRequestUri() for getPathInfo(), which returns only the path component, ignoring the query string.
// The Fix (Commit c1d0d56)
- $content = str_replace('"#', '"'.request()->getRequestUri().'#', $content);
+ $content = str_replace('"#', '"'.request()->getPathInfo().'#', $content);Exploiting this requires zero authentication and zero fancy tools. You just need a web browser or curl. The goal is to inject a Blade echo statement {{ ... }} into the query string. When the server processes the page, it sees our payload as part of the HTML structure it constructed to "fix" the links, and the Blade engine evaluates it.
Here is the attack chain visualized:
To pull this off, the targeted documentation page must actually have at least one internal anchor link (e.g., #introduction) for the str_replace to trigger. Since almost all documentation pages have headers that generate these anchors, the attack surface is effectively "every page."
The Payload:
curl "http://target.com/docs/1.0?{{system('cat /etc/passwd')}}"If successful, the response body won't just contain the documentation; it will contain the contents of /etc/passwd rendered right inside the href attribute or seemingly dumped onto the page depending on where the anchor tag sits.
This is a CVSS 10.0 for a reason. It is unauthenticated Remote Code Execution. If your application is running as www-data, the attacker is now www-data. If you are running as root (please don't do that), the attacker owns the box.
In a Laravel context, RCE is particularly devastating. An attacker can:
.env: Steal database credentials, AWS keys, and APP_KEYs.public/shell.php.The EPSS score is already climbing past 16%, indicating that automated scanners and botnets are likely already looking for this. It's low-hanging fruit: a simple GET request that yields a shell.
If you are using saleem-hadad/larecipe, check your composer.lock immediately. If the version is below 2.8.1, you are vulnerable.
Primary Mitigation: Update the package via Composer:
composer update saleem-hadad/larecipeEmergency Mitigation (WAF):
If you cannot deploy code right now, configure your WAF (Cloudflare, AWS WAF, ModSecurity) to block any request query strings containing {{ or }}. While this won't fix the underlying bug, it will block the most obvious Blade injection attempts.
Developer Takeaway:
Never, ever, ever trust request()->getRequestUri() or $_SERVER['REQUEST_URI'] inside a context that will be passed to a template engine or an eval() equivalent. Always treat the URL as hostile user input.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
LaRecipe Saleem Hadad | < 2.8.1 | 2.8.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1336 (SSTI) |
| CVSS v3.1 | 10.0 (Critical) |
| Attack Vector | Network (HTTP GET) |
| EPSS Score | 16.76% |
| Exploit Status | PoC Available |
| Impact | Remote Code Execution |
Improper Neutralization of Special Elements Used in a Template Engine
An authentication bypass and token leakage vulnerability exists in TSDProxy before version 1.4.4. The application unconditionally forwards its internal administrative token to all proxied backend services when identity headers are enabled. Attackers with control over an upstream backend can capture this token and replay it to the local management API to achieve full administrative control over the proxy engine.
A high-severity Stored Cross-Site Scripting (XSS) vulnerability exists in SiYuan prior to version 3.7.0. The vulnerability is located within the server-side Markdown-to-HTML parsing component for the Bazaar marketplace packages. Due to an incomplete event-handler attribute blocklist in the lute parsing engine and a lack of client-side DOM sanitization, malicious package authors can bypass restrictions using modern HTML5 event handlers. When an authenticated administrator views a malicious package, the embedded JavaScript runs in the administrator origin, allowing unauthorized workspace access, local file reading, and remote API execution.
A DNS-rebinding Time-of-Check to Time-of-Use (TOCTOU) vulnerability exists in the mcp-atlassian server before version 0.17.0. The server processes unauthenticated client-supplied URLs via custom headers, validating the destination IP but failing to pin the resolved address before connecting. This allows remote adjacent-network attackers to achieve Server-Side Request Forgery (SSRF) and access restricted resources or cloud metadata services.
A high-severity denial-of-service vulnerability in @libp2p/gossipsub prior to version 16.0.0 allows unauthenticated remote attackers to trigger event loop starvation and complete node freeze by exploiting unbounded protobuf decoding limits and nested synchronous array iteration loops.
CVE-2026-49858 is a vulnerability in API Platform Core's JSON:API and HAL item normalizers where conditionally secured attributes are cached globally in memory. When deployed in long-running PHP execution environments such as FrankenPHP worker mode, Swoole, or RoadRunner, this persistent caching bypasses property-level security constraints, allowing unprivileged users to access sensitive, unauthorized fields cached during privileged requests.
CVE-2026-5078 is a log injection vulnerability in Morgan, the widely deployed Node.js HTTP request logging middleware. The vulnerability arises because the ':remote-user' logging token decodes and outputs basic authentication usernames containing control characters, such as Carriage Return (CR) and Line Feed (LF), without sanitization. An unauthenticated attacker can bypass native HTTP header parsers by Base64-encoding CRLF sequences in the Authorization header. When Morgan logs the request, these control characters force newlines in the log stream, enabling log forging, SIEM evasion, and system activity spoofing.