Question 19 · Section 13

Can you change String value via reflection?

Technically — yes, through the Reflection API you can change the internal contents of a string, but this is very bad practice.

Language versions: English Russian Ukrainian

Junior Level

Technically — yes, through the Reflection API you can change the internal contents of a string, but this is very bad practice.

String s = "Hello";
// Access the private field value
// In Java 8 and earlier the field was char[] value. Starting with Java 9 (Compact Strings) — byte[] value.
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
byte[] value = (byte[]) field.get(s);
value[0] = 'J'; // Change 'H' to 'J'
System.out.println(s); // Prints "Jello"

Why this is bad:

  • The string changes everywhere where "Hello" is used (string pool)
  • hashCode breaks — the string gets lost in HashMap
  • This is a JVM security violation

WARNING: This technique MUST NOT be used in production code. It is a security violation that breaks the JVM. Educational purposes only.


Middle Level

Consequences

  1. String Pool breakage — the string changes everywhere the literal is used (logs, configs, class names)

  2. HashMap breakageString caches hashCode. After changing the value array, the string contents change but the hash remains the old one → the object cannot be found in HashMap

  3. Security Bypass — security checks (file access, URLs) are based on strings. Changing a string “after validation” is a classic vulnerability

Protection in modern JDKs

In Java 17+, access to internal fields of java.base via reflection is blocked by the module system (Project Jigsaw). You get InaccessibleObjectException.

You can bypass it with launch flags (--add-opens java.base/java.lang=ALL-UNNAMED), but this is not feasible in production.


Senior Level

Full attack example

String s = "admin";
Field valueField = String.class.getDeclaredField("value");
valueField.setAccessible(true);
byte[] value = (byte[]) valueField.get(s);
// Change "admin" to "hacker"
value[0] = 'h'; value[1] = 'a'; value[2] = 'c';
value[3] = 'k'; value[4] = 'e'; value[5] = 'r';

Deep consequences

  • ClassLoader pollution — class names, loaders, paths — everything can be compromised
  • Security Manager — if used, checks can be bypassed
  • SerialVersionUID — depends on class name, can be compromised

Evolution of protection

  • Java 8 and earlier: setAccessible(true) worked without restrictions
  • Java 9: module system restricted access to java.base
  • Java 16+: InaccessibleObjectException by default
  • Java 17+: --illegal-access=deny by default

Summary for Senior

  • Reflection attack on String — an example of how low-level manipulations destroy high-level guarantees
  • Modern JDKs (17+) block this at the module level
  • In production with correct flags this is impossible
  • For Senior: this illustrates the importance of encapsulation at all levels

Interview Cheat Sheet

Must know:

  • Technically possible via setAccessible(true) on the value field, but it’s a security violation
  • Consequences: String Pool breakage (changes everywhere), hashCode breaks (lost in HashMap), Security Bypass
  • Java 9+: module system restricted access; Java 16+: InaccessibleObjectException by default
  • Java 17+: --illegal-access=deny — reflection to java.base is blocked
  • Can be bypassed with flags (--add-opens), but not feasible in production
  • This MUST NOT be used in production — educational purposes only

Frequent follow-up questions:

  • Does it work in Java 17+? — No, InaccessibleObjectException without --add-opens
  • What breaks if you change a string? — All uses of that literal, hashCode in HashMap, Security Manager
  • What is ClassLoader pollution? — Class names, loaders, paths — everything can be compromised
  • Does SerialVersionUID depend on this? — Yes, depends on class name, can be compromised

Red flags (do NOT say):

  • “This is a normal production technique” — it’s a JVM security violation
  • “Reflection works in any version” — in Java 16+ it’s blocked for java.base
  • “Only this string changes” — ALL instances of that literal in the pool change
  • “You can add a flag in production” — --add-opens java.base/java.lang=ALL-UNNAMED — security risk

Related topics:

  • [[4. Why is String class immutable]]
  • [[5. What are the consequences of String immutability]]
  • [[18. How does String pool work and how is it related to immutability]]
  • [[8. Is it enough to make all fields final for immutability]]