InlineModelResolver.uniqueName throws StringIndexOutOfBoundsException for titles starting with a separator (camelCaseFlattenNaming)
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Start in modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/InlineModelResolver.java at uniqueName(String key), then trace its caller resolveModelName(title, key). Reproduce through OpenAPIV3Parser with flattening and camelCaseFlattenNaming enabled using a title beginning with a separator or an empty title; done means valid input no longer throws and produces a non-empty model name.
Written by the indexing model from the issue text.
Description
Summary
InlineModelResolver.uniqueName() crashes with an uncaught StringIndexOutOfBoundsException when camelCaseFlattenNaming is enabled and the input key (a schema title, or a derived fallback name) is empty or starts with one of the separator characters (-, _, |, whitespace). The first token produced by key.split(...) is then the empty string, and substring(0, 1) is called on it unconditionally.
Static-analysis finding against current master; not executed here.
Location
- File:
modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/InlineModelResolver.java - Function:
uniqueName(String key), lines ~441-455; specifically:
for (int i = 0; i < key.split("[-|\\s|_]").length; i++) {
uniqueKey = key.split("[-|\\s|_]")[i];
uniqueKey = uniqueKey.substring(0, 1).toUpperCase() + uniqueKey.substring(1); // <-- throws
- Reached from
resolveModelName(title, key)(~line 418), which prefersuniqueName(title)whenevertitle != null.
Problem
Java's split() removes trailing empty strings but keeps leading ones. For any key whose first character is a separator - e.g. " foo", "-foo", "_foo" - or for the empty string "" (split result [""]), element 0 of the split array is "". The loop body then executes "".substring(0, 1), which throws StringIndexOutOfBoundsException: begin 1, end 0, length 0. There is no guard for empty tokens anywhere in the loop.
Because resolveModelName() passes the schema's free-form title straight into uniqueName(), any inline schema whose title begins with such a character (or is "") triggers this when flattening runs with camel-case naming enabled.
Trigger / Reproduction
Static analysis only; not run here. Trigger conditions per the code paths above:
ParseOptions options = new ParseOptions();
options.setResolve(true);
options.setFlatten(true);
options.setCamelCaseFlattenNaming(true);
new OpenAPIV3Parser().readContents(spec, null, options);
with an inline schema whose title starts with a separator or is empty, e.g.:
paths:
/things:
post:
requestBody:
content:
application/json:
schema:
type: object
title: " my model" # or "-", "_x", ""
properties:
name: { type: string }
" my model".split("[-|\s|_]") yields ["", "my", "model"]; iteration 0 calls "".substring(0, 1) and throws.
Note that "" as title also crashes here, which overlaps with the empty-title report in #2118 - but #2118 describes the degenerate empty component name outcome (default options), not this exception path with camelCaseFlattenNaming=true.
Expected Behavior
A malformed/unusual title should degrade gracefully: skip empty tokens (or fall back to the provided fallback key / a synthesized name like inline_object) instead of throwing an unhandled runtime exception out of flatten().
Actual Behavior
StringIndexOutOfBoundsException propagates from InlineModelResolver.flatten(); parsing aborts even though the document itself is valid.
Impact
Library consumers using the documented flatten + camelCaseFlattenNaming combination get a hard failure on valid documents containing titles with leading separators/spaces (free-form strings users legitimately control, e.g. " LED status"). Since OpenAPIV3Parser catches and logs exceptions in some paths (catch (Exception e) around resolving), the failure can also surface merely as a silently un-flattened/partially processed API instead of clean output, depending on call site.
Suggested Direction
Inside the loop, skip empty tokens before calling substring (e.g. if (uniqueKey.isEmpty()) continue;), and after concatenation fall back to a non-empty default name if the sanitized result is blank. That fixes both the exception and the adjacent blank-name outcome from #2118 for the camel-case path.
Evidence
InlineModelResolver.javalines 444-452: unconditionalsubstring(0, 1)on each split token; no empty-token guard.- Java
String.splitsemantics retain leading empty strings (only trailing empties are removed). resolveModelName()line 422:titlewins over the fallback key whenever non-null, so user-controlled titles flow directly into the vulnerable code.
- Dominant language
- Java
- Stars
- 867
- Forks
- 560
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 7
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from swagger-api/swagger-parser
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
swagger-api/swagger-parser#2168 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
swagger-api/swagger-parser#1922 · 2 comments · 1 reaction ·
-
[Bug]: Regression: resolveFully fails when components key does not match external file basename OpenBug
Difficulty 4/5 3-5 days Newbie friendliness 58/100
swagger-api/swagger-parser#2399 · 3 comments ·
-
Bug
Difficulty 4/5 3-5 days Newbie friendliness 48/100
swagger-api/swagger-parser#2395 ·
-
Bug
Difficulty 4/5 3-5 days Newbie friendliness 55/100
swagger-api/swagger-parser#2374 ·
All issues in swagger-api/swagger-parser
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
infinispan/infinispan#18150 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
opensearch-project/k-NN#3597 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100