Precision pass on auth and resource analysis (#63)

This commit is contained in:
Eli Peter 2026-05-03 13:51:46 -04:00 committed by GitHub
parent 064801a3a4
commit c7c5e0f3a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 4248 additions and 138 deletions

View file

@ -0,0 +1,81 @@
// Nyx CVE benchmark fixture (patched).
// CVE: GHSA-h8cj-hpmg-636v
// Project: appsmith (appsmithorg/appsmith)
// License: Apache-2.0
// Advisory: https://github.com/advisories/GHSA-h8cj-hpmg-636v
// Patched: c8023ba4b3b54204ff3309c9e5c33664ad15ba32
// app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/ce/FilterDataServiceCE.java:60-65,632-647
//
// Patched dropTable() now calls validateFilterTempTableName(tableName)
// before constructing the SQL string. The validator rejects any input
// that does not match `^tbl_[A-Z]{16}$`, the exact shape produced by
// FilterDataServiceCE.generateTable() (`tbl_` + 16 random uppercase
// alphabetics). Anything caller-supplied that is not a real generated
// table name throws and SQL never runs.
//
// Trims:
// - same as vulnerable.java (imports / generateTable scaffolding /
// connection-cache helpers).
// - AppsmithPluginException replaced with java.lang.IllegalArgumentException
// to keep the fixture self-contained; the upstream throw still rejects
// the request before it can reach SQL.
// - StringUtils.isBlank() inlined as `tableName == null || tableName.isBlank()`
// to keep the regex-allowlist as the load-bearing sanitiser without
// pulling in commons-lang3.
//
// Patched-fix simplification: the entry-point Servlet controller and
// the dropTable + executeDbQuery code are kept verbatim from the
// surrounding upstream context; the validator + Pattern.compile are
// copied byte-for-byte from the patched commit.
package com.appsmith.external.services.ce;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
class FilterController {
private final FilterDataServiceCE service = new FilterDataServiceCE();
public void drop(HttpServletRequest req) {
String tableName = req.getParameter("tableName");
service.dropTable(tableName);
}
}
class FilterDataServiceCE {
/**
* Names produced by {@link #generateTable(Map)}: {@code tbl_} plus 16 alphabetic characters (see
* {@link RandomStringUtils#randomAlphabetic(int)} + uppercase). Used to reject untrusted input in dynamic SQL.
*/
private static final Pattern FILTER_TEMP_TABLE_NAME_PATTERN = Pattern.compile("^tbl_[A-Z]{16}$");
public void dropTable(String tableName) {
validateFilterTempTableName(tableName);
String dropTableQuery = "DROP TABLE " + tableName + ";";
executeDbQuery(dropTableQuery);
}
private static void validateFilterTempTableName(String tableName) {
if (tableName == null || tableName.isBlank()
|| !FILTER_TEMP_TABLE_NAME_PATTERN.matcher(tableName).matches()) {
throw new IllegalArgumentException("Invalid filter temporary table name");
}
}
/** Long-lived field; upstream caches the H2 connection across calls. */
private Connection connection;
private void executeDbQuery(String query) {
try (Statement statement = connection.createStatement()) {
statement.execute(query);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
}

View file

@ -0,0 +1,67 @@
// Nyx CVE benchmark fixture.
// CVE: GHSA-h8cj-hpmg-636v
// Project: appsmith (appsmithorg/appsmith)
// License: Apache-2.0
// Advisory: https://github.com/advisories/GHSA-h8cj-hpmg-636v
// Vulnerable: b142de499faa31b8391bc8dba40daa9519ebac1e
// app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/ce/FilterDataServiceCE.java:509-519,625-630
//
// FilterDataServiceCE exposes dropTable(String) which concatenates the
// caller-supplied table name into a "DROP TABLE …;" statement and runs
// it on the in-memory H2 connection via Statement.execute. The advisory
// confirms a reachable code path passes user input through to this
// helper, giving an attacker primary SQL injection on the H2 filter db.
//
// Trims:
// - imports for AppsmithPlugin / Jackson / commons-lang3 / log4j /
// SerializationUtils that the dropTable + executeDbQuery slice does
// not touch (lines 1-40 of upstream).
// - the ~900 lines of generateTable / generateSchema / generateLogicalQuery
// / insertReadyData / select-result helpers around the dropTable site,
// none of which the attacker reaches.
// - the H2 connection-cache and DriverManager.getConnection setup; the
// fixture stubs checkAndGetConnection() since the SQLi is in the call
// to Statement.execute and not the connection bootstrap.
// - the actual REST controller that reaches dropTable() lives in a
// separate file in upstream and routes through several plugin layers.
// The fixture stands in a minimal Servlet-style entry point
// (HttpServletRequest.getParameter) to model the user-input source;
// the load-bearing dropTable + executeDbQuery code below is verbatim
// from upstream.
package com.appsmith.external.services.ce;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.http.HttpServletRequest;
class FilterController {
private final FilterDataServiceCE service = new FilterDataServiceCE();
public void drop(HttpServletRequest req) {
String tableName = req.getParameter("tableName");
service.dropTable(tableName);
}
}
class FilterDataServiceCE {
/** Long-lived field; upstream caches the H2 connection across calls. */
private Connection connection;
public void dropTable(String tableName) {
String dropTableQuery = "DROP TABLE " + tableName + ";";
executeDbQuery(dropTableQuery);
}
private void executeDbQuery(String query) {
try (Statement statement = connection.createStatement()) {
statement.execute(query);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
}