NationalSecurityAgency/ghidra · error · IOException

Bad characters in requested category type

Error message

Bad characters in requested category type

What it means

Thrown by InstallTagRequest.saveXml when serializing a BSim 'installtag' request whose tag_name fails CategoryRecord.enforceTypeCharacters. That validator permits only letters, digits, space, '.', '_', ':', '/', '(' and ')', and rejects null/empty strings. BSim enforces this because the tag name flows into PostgreSQL/ELASTIC category columns and XML attributes that must stay injection-free and round-trippable.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/protocol/InstallTagRequest.java:51

	public ResponseInfo installresponse;
	
	public InstallTagRequest() {
		super("installtag");
		tag_name = "";
	}
	
	@Override
	public void buildResponseTemplate() {
		if (response == null) {
			response = installresponse = new ResponseInfo();
		}
	}
	
	@Override
	public void saveXml(Writer fwrite) throws IOException {
		if (!CategoryRecord.enforceTypeCharacters(tag_name)) {
			throw new IOException("Bad characters in requested category type");
		}
		fwrite.append('<').append(name);
		fwrite.append('>');
		fwrite.append(tag_name);
		fwrite.append("</").append(name).append(">\n");
	}

	@Override
	public void restoreXml(XmlPullParser parser, LSHVectorFactory vectorFactory) throws LSHException {
		parser.start(name);
		tag_name = parser.end().getText();
	}

}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Sanitize tag_name with CategoryRecord.enforceTypeCharacters(tag_name) before populating the request, and reject/clean the input if it returns false.
  2. Strip or replace disallowed characters (e.g. replace '-' and ',' with '_') before assigning tag_name.
  3. Ensure tag_name is non-null and non-empty; the default constructor sets it to "" which will always fail.
  4. If the name must contain unusual characters, encode it before install and decode on read.

Example fix

// before
InstallTagRequest req = new InstallTagRequest();
req.tag_name = "my-tag,1"; // '-' and ',' not allowed
req.saveXml(writer);

// after
InstallTagRequest req = new InstallTagRequest();
String name = "my-tag,1".replace('-', '_').replace(',', '_');
if (!CategoryRecord.enforceTypeCharacters(name)) {
    throw new IllegalArgumentException("Invalid tag name: " + name);
}
req.tag_name = name;
req.saveXml(writer);
Defensive patterns

Strategy: validation

Validate before calling

import ghidra.features.bsim.query.description.CategoryRecord;

boolean valid = tag_name != null
    && !tag_name.isEmpty()
    && CategoryRecord.enforceTypeCharacters(tag_name);
if (!valid) {
    // reject or sanitize before constructing InstallTagRequest
    tag_name = tag_name.replaceAll("[^A-Za-z0-9 .:_/()]", "_");
}

Type guard

// Java: predicate usable as a guard
static boolean isAcceptableTagName(String s) {
    return s != null && !s.isEmpty() && CategoryRecord.enforceTypeCharacters(s);
}

Try / catch

try {
    req.saveXml(writer);
} catch (IOException e) {
    if (e.getMessage().contains("Bad characters")) {
        // sanitize tag_name and retry once
        req.tag_name = req.tag_name.replaceAll("[^A-Za-z0-9 .:_/()]", "_");
        req.saveXml(writer);
    } else throw e;
}

Prevention

When it happens

Trigger: Constructing an InstallTagRequest, setting tag_name to a value containing characters such as quotes, '<', '>', ';', commas, dashes, or null/empty, then calling saveXml(Writer). Also triggered by an empty or null tag_name since enforceTypeCharacters returns false for both.

Common situations: Passing a user-supplied label verbatim into a BSim tag install command. Copying a symbol/function name that contains shell or XML metacharacters. Forgetting to initialize tag_name (it defaults to "" which fails).

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/abb91cd606537117. Report an issue: GitHub.