appendices.md

August 11, 2025 · View on GitHub

Appendices

Security Considerations

Unicode MessageFormat patterns are meant to allow a message to include any string value which users might normally wish to use in their environment. Programming languages and other environments vary in what characters are permitted to appear in a valid string. In many cases, certain types of characters, such as invisible control characters, require escaping by these host formats. In other cases, strings are not permitted to contain certain characters at all. Since messages are subject to the restrictions and limitations of their host environments, their serializations and resource formats, that might be sufficient to prevent most problems. However, MessageFormat itself does not supply such a restriction.

MessageFormat messages permit nearly all Unicode code points to appear in literals, including the text portions of a pattern. This means that it can be possible for a message to contain invisible characters (such as bidirectional controls, ASCII control characters in the range U+0000 to U+001F, or characters that might be interpreted as escapes or syntax in the host format) that abnormally affect the display of the message when viewed as source code, or in resource formats or translation tools, but do not generate errors from MessageFormat parsers or processing APIs.

Bidirectional text containing right-to-left characters (such as used for Arabic or Hebrew) also poses a potential source of confusion for users. Since MessageFormat's syntax makes use of keywords and symbols that are left-to-right or consist of neutral characters (including characters subject to mirroring under the Unicode Bidirectional Algorithm), it is possible to create messages that, when displayed in source code, or in resource formats or translation tools, have a misleading appearance or are difficult to parse visually.

For more information, see [UTS#55] Unicode Source Code Handling.

MessageFormat implementations might allow end-users to install selectors, functions, or markup from third-party sources. Such functionality can be a vector for various exploits, including buffer overflow, code injection, user tracking, fingerprinting, and other types of bad behavior. Any installed code needs to be appropriately sandboxed. In addition, end-users need to be aware of the risks involved.

Non-normative Examples

Pattern Selection Examples

Selection Example 1

Presuming a minimal implementation which only supports :string function which matches keys by using string comparison, and a formatting context in which the variable reference $foo resolves to the string 'foo' and the variable reference $bar resolves to the string 'bar', pattern selection proceeds as follows for this message:

.input {$foo :string}
.input {$bar :string}
.match $foo $bar
bar bar {{All bar}}
foo foo {{All foo}}
* * {{Otherwise}}
  1. Each selector is resolved, yielding the list res = {foo, bar}.
  2. bestVariant is set to UNSET.
  3. keys is set to {bar, bar}.
  4. match is set to SelectorsMatch({foo, bar}, {bar, bar}). The result of SelectorsMatch({foo, bar}, {bar, bar}) is determined as follows:
    1. result is set to true.
    2. i is set to 0.
    3. k is set to the string bar.
    4. sel is set to a resolved value corresponding to the string foo.
    5. Match(sel, 'bar') is false.
    6. The result of SelectorsMatch({foo, bar}, {bar, bar}) is false. Thus, match is set to false.
  5. keys is set to {foo, foo}.
  6. match is set to SelectorsMatch({foo, bar}, {foo, foo}). The result of SelectorsMatch({foo, bar}, {foo, foo}) is determined as follows:
    1. result is set to true.
    2. i is set to 0.
    3. k is set to the string foo.
    4. sel is set to a resolved value corresponding to the string foo.
    5. Match(sel, 'foo') is true.
    6. i is set to 1.
    7. k is set to the string foo.
    8. sel is set to a resolved value corresponding to the string bar.
    9. Match(sel, 'bar') is false.
    10. The result of SelectorsMatch({foo, bar}, {foo, foo}) is false.
  7. keys is set to * *.
  8. The result of SelectorsMatch({foo, bar}, {*, *}) is determined as follows:
    1. result is set to true.
    2. i is set to 0.
    3. i is set to 1.
    4. i is set to 2.
    5. The result of SelectorsMatch({foo, bar}, {*, *}) is true.
  9. bestVariant is set to the variant * * {{Otherwise}}
  10. The pattern Otherwise is selected.
Selection Example 2

Alternatively, with the same implementation and formatting context as in Example 1, pattern selection would proceed as follows for this message:

.input {$foo :string}
.input {$bar :string}
.match $foo $bar
* bar {{Any and bar}}
foo * {{Foo and any}}
foo bar {{Foo and bar}}
* * {{Otherwise}}
  1. Each selector is resolved, yielding the list res = {foo, bar}.
  2. bestVariant is set to UNSET.
  3. keys is set to {*, bar}.
  4. match is set to SelectorsMatch({foo, bar}, {*, bar}) The result of SelectorsMatch({foo, bar}, {*, bar}) is determined as follows:
    1. result is set to true.
    2. i is set to 0.
    3. i is set to 1.
    4. k is set to the string bar.
    5. sel is set to a resolved value corresponding to the string bar.
    6. Match(sel, 'bar') is true.
    7. i is set to 2.
    8. The result of SelectorsMatch({foo, bar}, {*, bar}) is true.
  5. bestVariant is set to the variant * bar {{Any and bar}}.
  6. keys is set to {foo, *}.
  7. match is set to SelectorsMatch({foo, bar}, {foo, *}). The result of SelectorsMatch({foo, bar}, {foo, *}) is determined as follows:
    1. result is set to true.
    2. i is set to 0.
    3. k is set to the string foo.
    4. sel is set to a resolved value corresponding to the string foo.
    5. Match(sel, 'foo') is true.
    6. i is set to 1.
    7. i is set to 2.
    8. The result of SelectorsMatch({foo, bar}, {foo, *}) is true.
  8. bestVariantKeys is set to {*, bar}.
  9. SelectorsCompare({foo, bar}, {foo, *}, {*, bar}) is determined as follows:
    1. result is set to false.
    2. i is set to 0.
    3. key1 is set to foo.
    4. key2 is set to '*'
    5. The result of SelectorsCompare({foo, bar}, {foo, *}, {*, bar}) is true.
  10. bestVariant is set to foo * {{Foo and any}}.
  11. keys is set to {foo, bar}.
  12. match is set to SelectorsMatch({foo, bar}, {foo, bar}).
    1. match is true (details elided)
  13. bestVariantKeys is set to {foo, *}.
  14. SelectorsCompare({foo, bar}, {foo, bar}, {foo, *}) is determined as follows:
    1. result is set to false.
    2. i is set to 0.
    3. key1 is set to foo.
    4. key2 is set to foo.
    5. k1 is set to foo.
    6. k2 is set to foo.
    7. sel is set to a resolved value corresponding to foo.
    8. i is set to 1.
    9. key1 is set to bar.
    10. key2 is set to *.
    11. The result of SelectorsCompare({foo, bar}, {foo, bar}, {foo, *}) is true.
  15. bestVariant is set to foo bar {{Foo and bar}}.
  16. keys is set to * *.
  17. match is set to true (details elided).
  18. bestVariantKeys is set to foo bar.
  19. SelectorsCompare({foo, bar}, {*, *}, {foo, bar}} is false (details elided).

The pattern {{Foo and bar}} is selected.

Selection Example 3

A more-complex example is the matching found in selection APIs such as ICU's PluralFormat. Suppose that this API is represented here by the function :number. This :number function can match a given numeric value to a specific number literal and also to a plural category (zero, one, two, few, many, other) according to locale rules defined in CLDR.

Given a variable reference $count whose value resolves to the number 1 and an en (English) locale, the pattern selection proceeds as follows for this message:

.input {$count :number}
.match $count
one {{Category match for {$count}}}
1   {{Exact match for {$count}}}
*   {{Other match for {$count}}}
  1. Each selector is resolved, yielding the list {1}.
  2. bestVariant is set to UNSET.
  3. keys is set to {one}.
  4. match is set to SelectorsMatch({1}, {one}). The result of SelectorsMatch({1}, {one}) is determined as follows:
    1. result is set to true.
    2. i is set to 0.
    3. k is set to one.
    4. sel is set to 1.
    5. Match(sel, one) is true.
    6. i is set to 1.
    7. The result of SelectorsMatch({1}, {one}) is true.
  5. bestVariant is set to one {{Category match for {$count}}}.
  6. keys is set to 1.
  7. match is set to SelectorsMatch({1}, {one}).
    1. The details are the same as the previous case, as Match(sel, 1) is also true.
  8. bestVariantKeys is set to {one}.
  9. SelectorsCompare({1}, {1}, {one}) is determined as follows:
    1. result is set to false.
    2. i is set to 0.
    3. key1 is set to 1.
    4. key2 is set to one.
    5. k1 is set to 1.
    6. k2 is set to one.
    7. sel is set to 1.
    8. result is set to BetterThan(sel, 1, one), which is true.
      1. NOTE: The specification of the :number selector function states that the exact match 1 is a better match than the category match one.
    9. bestVariant is set to 1 {{Exact match for {$count}}}.
  10. keys is set to *
    1. Details elided; since * is the catch-all key, BetterThan({1}, {1}, {*}) is false.
  11. The pattern {{Exact match for {$count}}} is selected.

Acknowledgments

Special thanks to the following people for their contributions to making the Unicode MessageFormat Standard. The following people contributed to our github repo and are listed in order by contribution size:

Addison Phillips, Eemeli Aro, Romulo Cintra, Tim Chevalier, Stanisław Małolepszy, Elango Cheran, Richard Gibson, Mark Davis, Mihai Niță, Steven R. Loomis, Shane F. Carr, Matt Radbourne, Caleb Maclennan, David Filip, Christopher Dieringer, Danny Gleckler, Bruno Haible, Daniel Minor, George Rhoten, Ujjwal Sharma, Markus Scherer, Lionel Rowe, Luca Casonato, Daniel Ehrenberg, Zibi Braniecki, and Rafael Xavier de Souza.

Eemeli Aro is the current chair of the working group. Addison Phillips was chair of the working group from January 2023 to July 2025. Prior to 2023, the group was governed by a chair group, consisting of Romulo Cintra, Elango Cheran, Mihai Niță, David Filip, Nicolas Bouvrette, Stanisław Małolepszy, Rafael Xavier de Souza, Addison Phillips, and Daniel Minor. Romulo Cintra chaired the chair group.