From c2ea9cc40319675766808d3136cb452c2b7f32d8 Mon Sep 17 00:00:00 2001 From: Madhur Jain <87946372+jmadhur87@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:19:35 +0530 Subject: [PATCH 1/2] chore: Update int to Long_Int (#1081) --- .../cli/cmd/AbstractSSCIssueTemplateUpdateCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue_template/cli/cmd/AbstractSSCIssueTemplateUpdateCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue_template/cli/cmd/AbstractSSCIssueTemplateUpdateCommand.java index 1ec99fa9144..ac8a70ae2bb 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue_template/cli/cmd/AbstractSSCIssueTemplateUpdateCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue_template/cli/cmd/AbstractSSCIssueTemplateUpdateCommand.java @@ -16,7 +16,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.node.LongNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fortify.cli.common.json.JsonHelper; import com.fortify.cli.common.output.transform.IActionCommandResultSupplier; @@ -63,7 +63,7 @@ protected ArrayNode getCustomTagIds(UnirestInstance unirest, SSCIssueTemplateDes currentTags, addTagsMixin.getTagSpecs(), rmTagsMixin.getTagSpecs() - ).map(tag -> new IntNode(Integer.valueOf(tag.getId()))).collect(JsonHelper.arrayNodeCollector()); + ).map(tag -> new LongNode(Long.valueOf(tag.getId()))).collect(JsonHelper.arrayNodeCollector()); } @Override From c9557ad4aa36985dde98082faa5562edfe945b2b Mon Sep 17 00:00:00 2001 From: mjain6 Date: Mon, 21 Sep 2026 15:25:06 +0530 Subject: [PATCH 2/2] Add FAA identifed Vuln fix --- .../helper/arg/MCPToolArgHandlerQuery.java | 16 ++++++++++++-- .../writer/record/impl/RecordWriterTable.java | 22 +++++++++++++++++-- .../cli/cmd/SSCUserCreateLocalCommand.java | 5 ++++- .../cli/cmd/SSCUserUpdateLocalCommand.java | 5 ++++- .../action/helper/SSCActionSpelFunctions.java | 5 ++++- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/fcli-core/fcli-ai-assist/src/main/java/com/fortify/cli/ai_assist/mcp/helper/arg/MCPToolArgHandlerQuery.java b/fcli-core/fcli-ai-assist/src/main/java/com/fortify/cli/ai_assist/mcp/helper/arg/MCPToolArgHandlerQuery.java index 326b4ae0ebc..1c068f76827 100644 --- a/fcli-core/fcli-ai-assist/src/main/java/com/fortify/cli/ai_assist/mcp/helper/arg/MCPToolArgHandlerQuery.java +++ b/fcli-core/fcli-ai-assist/src/main/java/com/fortify/cli/ai_assist/mcp/helper/arg/MCPToolArgHandlerQuery.java @@ -181,7 +181,19 @@ public String getFcliCmdArgs(Map toolArgs) { } private final void addQuery(ArrayList queries, String schemaPropertyName, String value) { - var fieldName = fieldsBySchemaPropertyName.getOrDefault(schemaPropertyName, schemaPropertyName); - queries.add(String.format("%s matches '%s'", fieldName, value)); + // Validate that schemaPropertyName is in the known set of safe fields (do not fall back to attacker-supplied name) + if ( !fieldsBySchemaPropertyName.containsKey(schemaPropertyName) ) { + throw new FcliSimpleException("Unknown query field '%s'; allowed fields are: %s", + schemaPropertyName, String.join(", ", fieldsBySchemaPropertyName.keySet())); + } + var fieldName = fieldsBySchemaPropertyName.get(schemaPropertyName); + // Escape backslashes first, then single quotes to prevent SpEL string literal breakout + var escapedValue = value.replace("\\", "\\\\") + .replace("'", "\\'"); + // Reject values containing unescaped double quotes or certain problematic characters that could break CLI token boundaries + if ( value.contains("\"") ) { + throw new FcliSimpleException("Query value contains unescaped double quote which is not allowed for CLI safety"); + } + queries.add(String.format("%s matches '%s'", fieldName, escapedValue)); } } \ No newline at end of file diff --git a/fcli-core/fcli-common-core/src/main/java/com/fortify/cli/common/output/writer/record/impl/RecordWriterTable.java b/fcli-core/fcli-common-core/src/main/java/com/fortify/cli/common/output/writer/record/impl/RecordWriterTable.java index 8ae3a716357..25d33434039 100644 --- a/fcli-core/fcli-common-core/src/main/java/com/fortify/cli/common/output/writer/record/impl/RecordWriterTable.java +++ b/fcli-core/fcli-common-core/src/main/java/com/fortify/cli/common/output/writer/record/impl/RecordWriterTable.java @@ -96,9 +96,27 @@ private String getColumnValue(ObjectNode formattedRecord, String property) { var node = formattedRecord.get(property); if ( node==null || node.isNull() ) { return "N/A"; } if ( node.isArray() ) { - return JsonHelper.stream((ArrayNode)node).map(n->n.asText()).collect(Collectors.joining(",")); + return JsonHelper.stream((ArrayNode)node).map(n->stripAnsiAndControlChars(n.asText())).collect(Collectors.joining(",")); } - return node.asText(); + return stripAnsiAndControlChars(node.asText()); + } + + /** + * Strip ANSI escape sequences and control characters from string to prevent terminal injection attacks. + * Preserves newlines and tabs as they may be used intentionally in table layout. + * Removes: ESC (0x1B) and C0 control chars (0x00-0x1F) except TAB (0x09) and LF (0x0A). + */ + private String stripAnsiAndControlChars(String input) { + if ( input == null || input.isEmpty() ) { return input; } + // Remove ANSI escape sequences and C0 control chars, preserving TAB and LF + StringBuilder result = new StringBuilder(); + for ( char c : input.toCharArray() ) { + // Keep printable chars and common whitespace (TAB, LF); skip ESC and other control chars + if ( (c >= 0x20 && c <= 0x7E) || c == 0x09 || c == 0x0A ) { + result.append(c); + } + } + return result.toString(); } @Override diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserCreateLocalCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserCreateLocalCommand.java index 053e0d35009..f8a65a4dee1 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserCreateLocalCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserCreateLocalCommand.java @@ -18,6 +18,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fortify.cli.common.cli.util.CommandGroup; +import com.fortify.cli.common.log.LogSensitivityLevel; +import com.fortify.cli.common.log.MaskValue; import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.ssc._common.output.cli.cmd.AbstractSSCJsonNodeOutputCommand; import com.fortify.cli.ssc._common.rest.ssc.SSCUrls; @@ -38,7 +40,8 @@ public class SSCUserCreateLocalCommand extends AbstractSSCJsonNodeOutputCommand @Option(names = {"--username"}, required = true) private String username; - @Option(names = {"--password"}, required = true) + @Option(names = {"--password"}, required = true, interactive = true, echo = false, arity = "0..1") + @MaskValue(sensitivity = LogSensitivityLevel.high, description = "PASSWORD") private String password; @Option(names = {"--firstname"}) private String firstName; diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserUpdateLocalCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserUpdateLocalCommand.java index f1baafd9bd4..cf137bf845f 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserUpdateLocalCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/cli/cmd/SSCUserUpdateLocalCommand.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fortify.cli.common.cli.util.CommandGroup; import com.fortify.cli.common.exception.FcliSimpleException; +import com.fortify.cli.common.log.LogSensitivityLevel; +import com.fortify.cli.common.log.MaskValue; import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.output.transform.IActionCommandResultSupplier; import com.fortify.cli.ssc._common.output.cli.cmd.AbstractSSCJsonNodeOutputCommand; @@ -47,7 +49,8 @@ public class SSCUserUpdateLocalCommand extends AbstractSSCJsonNodeOutputCommand private String lastName; @Option(names = {"--email"}) private String email; - @Option(names = {"--password"}) + @Option(names = {"--password"}, interactive = true, echo = false, arity = "0..1") + @MaskValue(sensitivity = LogSensitivityLevel.high, description = "PASSWORD") private String password; @Option(names = {"--password-never-expires", "--pne"}) private Boolean pwNeverExpires; diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/action/helper/SSCActionSpelFunctions.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/action/helper/SSCActionSpelFunctions.java index 23d51622d46..a50d2f73c34 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/action/helper/SSCActionSpelFunctions.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/action/helper/SSCActionSpelFunctions.java @@ -21,6 +21,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import javax.xml.XMLConstants; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -174,7 +175,9 @@ private final String processFpr(RawResponse r, Function consu private final void processAuditFvdl(InputStream is, Function consumer) throws XMLStreamException { var factory = XMLInputFactory.newInstance(); - factory.setXMLResolver(null); // Prevent XML External Entity Injection + // Disable DTD processing and external entity resolution to prevent XXE attacks + factory.setProperty(XMLInputFactory.SUPPORT_DTD, false); + factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); var reader = factory.createXMLStreamReader(is); while(reader.hasNext()) { int eventType = reader.next();