You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Injection: POST /ureport/designer/saveReportFile (persist malicious report XML to database)
Trigger: GET /ureport/preview?_u=<report> (HTML preview reads file and embeds contents in response)
Default Service: blade-report microservice, port 8108 (Cloud edition per official docs)
Impact
The blade-report module integrates UReport2 through blade-starter-report, which registers UReportServlet at /ureport/* and stores report definitions in the database via DatabaseProvider. UReport2 allows report designers to insert image cells whose source is a filesystem or classpath path.
During HTML preview, the report engine reads the attacker-controlled path through DefaultImageProvider (vendored in blade-starter-report), Base64-encodes the raw bytes, and inlines them directly into the generated HTML as a data: URI.
Because:
DatabaseProvider.saveReport() stores report XML without validating embedded <image-value> paths.
DefaultImageProvider.getImage() resolves paths starting with / relative to the webapp root and supports classpath: and /WEB-INF/ prefixes — with no allow-list or traversal check.
When width=0 and height=0 (the default), ImageUtils.getImageBase64Data()does not verify that the bytes form a valid image; it Base64-encodes any file unconditionally.
SpringBlade's UReportAuthFilter only verifies a valid BladeX session token — it does not restrict dangerous report operations such as saving arbitrary image paths or previewing reports.
An authenticated attacker (any user with a valid BladeX token who can reach /ureport/*) can read arbitrary files accessible to the blade-report JVM process:
Path prefix
Example
Readable targets on SpringBlade
/ (web-root relative + traversal)
/../../../../etc/passwd
OS files (/etc/passwd, C:\Windows\win.ini)
classpath:
classpath:application.yml
Spring Boot config, JDBC credentials, Nacos bootstrap settings
classpath:
classpath:bootstrap.yml
Cloud config secrets loaded by blade-report
/WEB-INF/
/WEB-INF/web.xml
Deployment descriptors (WAR deployments)
Impact summary:
Arbitrary Local File Read (CWE-22 / CWE-552): Database connection strings, Nacos/registry credentials, JWT signing keys, cloud access keys, SSH private keys, and other sensitive files on the blade-report server.
Information Disclosure (CWE-200): File contents are returned inline in the HTML preview response (data:image/png;base64,...), trivially decodable by the attacker.
SpringBlade ≤ 4.10.0 with blade-report service enabled
Valid BladeX authentication token (obtain via normal login)
blade-report default port: 8108
Step 1: Save a Malicious Report via saveReportFile
Craft a report XML containing an image cell whose source="text" path points to the target file. Keep width and height at 0 (default) so ImageIO validation is skipped.
Send the request to the blade-report service with a valid Blade-Auth token header. The content parameter must be URL-encoded (matching the designer JavaScript encodeURIComponent behavior):
POST /ureport/designer/saveReportFile HTTP/1.1Host: localhost:8108Blade-Auth: <valid_token>Content-Type: application/x-www-form-urlencodedfile=blade:lfi-winini.ureport.xml&content=<url_encoded_xml>
Screenshot placeholder: Burp request showing authenticated saveReportFile with image-value payload.
The report XML is persisted to the MySQL database via DatabaseProvider.saveReport() without any validation of the embedded image path:
// org.springblade.core.report.provider.DatabaseProviderpublicvoidsaveReport(Stringfile, Stringcontent) {
// ...reportFileEntity.setContent(content.getBytes()); // raw XML stored, image path uncheckedservice.saveOrUpdate(reportFileEntity);
}
Screenshot placeholder: 200 OK response / report saved in database.
Alternative injection (no database persistence):POST /ureport/designer/savePreviewData with the same XML, then use _u=p in Step 2.
SpringBlade-specific high-value paths to test after basic PoC:
Request the saved report through the preview endpoint:
GET /ureport/preview?_u=blade:lfi-winini.ureport.xml HTTP/1.1Host: localhost:8108Blade-Auth: <valid_token>
Screenshot placeholder: Preview request in Burp or browser.
During preview, HtmlPreviewServletAction.loadReport() → ReportBuilder.buildReport() → ImageValueCompute.compute() resolves the image path and reads the target file from the blade-report server filesystem.
Step 3: Extract File Contents from Response
Inspect the HTML response body. The image cell is rendered as:
This confirms successful arbitrary file read on the blade-report server via the UReport2 image rendering pipeline.
Root Cause Analysis
The vulnerability exists in the UReport2 image-loading code bundled inside SpringBlade's blade-starter-report. SpringBlade adds token-based authentication via UReportAuthFilter, but performs no input validation or sandboxing on report content or image paths.
1. SpringBlade stores malicious image paths without validation
DesignerServletAction.saveReportFile() URL-decodes the content parameter and passes it to DatabaseProvider.saveReport(), which writes the raw XML string to the database. The embedded <image-value><text> path is never inspected:
5. Insufficient access control in SpringBlade integration
UReportAuthFilter only checks whether the caller holds a valid BladeX token or session — it does not enforce role-based restrictions on designer/save/preview operations:
// org.springblade.core.report.filter.UReportAuthFilterprivatebooleanisTokenAuthenticated(HttpServletRequestrequest) {
LonguserId = AuthUtil.getUserId(request);
returnuserId != null && userId > 0; // any authenticated user passes
}
Attack chain summary:
Authenticated attacker
→ POST /ureport/designer/saveReportFile (inject image path in XML)
→ DatabaseProvider.saveReport() → MySQL (blade_report table)
→ GET /ureport/preview?_u=blade:...
→ ReportBuilder.buildReport()
→ ImageValueCompute → DefaultImageProvider.getImage()
→ FileInputStream / classpath Resource
→ ImageUtils.getImageBase64Data() (no image validation at 0×0)
→ HtmlProducer inlines Base64 in HTML response
→ Attacker decodes sensitive file contents
Remediation
Immediate Mitigation
Block designer and preview endpoints in production if report authoring is not required at runtime. Restrict at the Spring Cloud Gateway or reverse proxy:
/ureport/designer/*
/ureport/preview
Restrict UReport access by role — extend UReportAuthFilter to require an administrator/designer role, not merely a valid token.
Code-Level Fixes (recommended for blade-starter-report)
Restrict DefaultImageProvider to an allow-listed directory — resolve paths with Path.normalize() and verify the canonical path stays under a configured base directory; reject classpath:, /WEB-INF/, and any .. segments.
Always validate image content before encoding — call ImageIO.read() regardless of width/height; reject streams that are not valid image formats.
Sanitize report XML on save — in DatabaseProvider.saveReport() or a wrapper, reject <image-value> paths containing .., classpath:, /WEB-INF, or paths outside the allow-list.
Do not inline local file bytes in HTML preview — serve images through a dedicated endpoint using opaque cache keys instead of user-supplied paths.
These are independent vulnerabilities in the same blade-report UReport2 integration. Fixing XXE in ReportParser does not remediate this image-path file read.
Arbitrary File Read via Image Cell Path in SpringBlade blade-report /ureport/preview Endpoint
Affected Versions
blade-reportmodule (UReport2 integration viablade-starter-reportin blade-tool)com.bstek.ureport:ureport2-core/ureport2-console2.2.9 (bundled insideblade-starter-report)POST /ureport/designer/saveReportFile(persist malicious report XML to database)GET /ureport/preview?_u=<report>(HTML preview reads file and embeds contents in response)blade-reportmicroservice, port 8108 (Cloud edition per official docs)Impact
The
blade-reportmodule integrates UReport2 throughblade-starter-report, which registersUReportServletat/ureport/*and stores report definitions in the database viaDatabaseProvider. UReport2 allows report designers to insert image cells whose source is a filesystem or classpath path.During HTML preview, the report engine reads the attacker-controlled path through
DefaultImageProvider(vendored inblade-starter-report), Base64-encodes the raw bytes, and inlines them directly into the generated HTML as adata:URI.Because:
DatabaseProvider.saveReport()stores report XML without validating embedded<image-value>paths.DefaultImageProvider.getImage()resolves paths starting with/relative to the webapp root and supportsclasspath:and/WEB-INF/prefixes — with no allow-list or traversal check.width=0andheight=0(the default),ImageUtils.getImageBase64Data()does not verify that the bytes form a valid image; it Base64-encodes any file unconditionally.UReportAuthFilteronly verifies a valid BladeX session token — it does not restrict dangerous report operations such as saving arbitrary image paths or previewing reports.An authenticated attacker (any user with a valid BladeX token who can reach
/ureport/*) can read arbitrary files accessible to theblade-reportJVM process:/(web-root relative + traversal)/../../../../etc/passwd/etc/passwd,C:\Windows\win.ini)classpath:classpath:application.ymlclasspath:classpath:bootstrap.yml/WEB-INF//WEB-INF/web.xmlImpact summary:
data:image/png;base64,...), trivially decodable by the attacker.Steps to Reproduce
Environment
blade-reportservice enabledStep 1: Save a Malicious Report via
saveReportFileCraft a report XML containing an image cell whose
source="text"path points to the target file. Keepwidthandheightat0(default) soImageIOvalidation is skipped.Original XML payload (before URL-encoding):
Send the request to the blade-report service with a valid
Blade-Authtoken header. Thecontentparameter must be URL-encoded (matching the designer JavaScriptencodeURIComponentbehavior):The report XML is persisted to the MySQL database via
DatabaseProvider.saveReport()without any validation of the embedded image path:Alternative injection (no database persistence):
POST /ureport/designer/savePreviewDatawith the same XML, then use_u=pin Step 2.SpringBlade-specific high-value paths to test after basic PoC:
Step 2: Trigger File Read via HTML Preview
Request the saved report through the preview endpoint:
During preview,
HtmlPreviewServletAction.loadReport()→ReportBuilder.buildReport()→ImageValueCompute.compute()resolves the image path and reads the target file from the blade-report server filesystem.Step 3: Extract File Contents from Response
Inspect the HTML response body. The image cell is rendered as:
Base64-decode the
srcpayload to recover the plaintext file contents:This confirms successful arbitrary file read on the blade-report server via the UReport2 image rendering pipeline.
Root Cause Analysis
The vulnerability exists in the UReport2 image-loading code bundled inside SpringBlade's
blade-starter-report. SpringBlade adds token-based authentication viaUReportAuthFilter, but performs no input validation or sandboxing on report content or image paths.1. SpringBlade stores malicious image paths without validation
DesignerServletAction.saveReportFile()URL-decodes thecontentparameter and passes it toDatabaseProvider.saveReport(), which writes the raw XML string to the database. The embedded<image-value><text>path is never inspected:2. Preview triggers unrestricted file read via
DefaultImageProviderWhen preview is requested,
ImageValueComputepasses the stored path toImageUtils.getImageBase64Data():DefaultImageProvider(vendored inblade-starter-report) reads any supported path with no restriction:3. Default dimensions bypass image format validation
When
width=0andheight=0,ImageUtils.getImageBase64Data()skipsImageIO.read()and Base64-encodes any byte stream:4. File contents exfiltrated in HTML preview response
HtmlProducerembeds the Base64 data directly into the preview HTML returned to the attacker:5. Insufficient access control in SpringBlade integration
UReportAuthFilteronly checks whether the caller holds a valid BladeX token or session — it does not enforce role-based restrictions on designer/save/preview operations:Attack chain summary:
Remediation
Immediate Mitigation
Block designer and preview endpoints in production if report authoring is not required at runtime. Restrict at the Spring Cloud Gateway or reverse proxy:
Restrict UReport access by role — extend
UReportAuthFilterto require an administrator/designer role, not merely a valid token.Code-Level Fixes (recommended for
blade-starter-report)Restrict
DefaultImageProviderto an allow-listed directory — resolve paths withPath.normalize()and verify the canonical path stays under a configured base directory; rejectclasspath:,/WEB-INF/, and any..segments.Always validate image content before encoding — call
ImageIO.read()regardless of width/height; reject streams that are not valid image formats.Sanitize report XML on save — in
DatabaseProvider.saveReport()or a wrapper, reject<image-value>paths containing..,classpath:,/WEB-INF, or paths outside the allow-list.Do not inline local file bytes in HTML preview — serve images through a dedicated endpoint using opaque cache keys instead of user-supplied paths.
Example secure path resolution
Relationship to Other SpringBlade UReport Issues
testConnectionPOST /ureport/datasource/testConnectionPOST saveReportFile→GET loadReportPOST saveReportFile→GET /ureport/previewThese are independent vulnerabilities in the same
blade-reportUReport2 integration. Fixing XXE inReportParserdoes not remediate this image-path file read.References
Credit
Discovered by: B1cx