diff --git a/.gitattributes b/.gitattributes
index edf4192..00ba7c0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -9,3 +9,6 @@
*.pdf binary
*.png binary
*.zip binary
+
+# Preserve the historical wiki snapshot byte-for-byte, including old whitespace.
+docs/archive/wiki-2019/*.mediawiki -text whitespace=-blank-at-eol,-blank-at-eof
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..c6a4006
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,3 @@
+# Verified repository administrators with write access on 2026-09-26.
+# Requests review; mandatory code-owner approval is not enabled by this file.
+* @jmanico @jeremylong
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..b1a09dd
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,4 @@
+# Maintainer support and Foundation donations are distinct; see CONTRIBUTING.md.
+custom:
+ - https://manicode.com/funding.json
+ - https://owasp.org/donate
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
new file mode 100644
index 0000000..f0d7f75
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -0,0 +1,30 @@
+name: Ordinary bug report
+description: Report a reproducible non-security bug.
+title: "Bug: "
+body:
+ - type: markdown
+ attributes:
+ value: |
+ **Suspected vulnerability? Stop and use [SECURITY.md](https://github.com/OWASP/owasp-java-encoder/security/policy).**
+ This form is public. Do not include attack proofs, credentials, personal data or private URLs.
+ - type: input
+ id: environment
+ attributes:
+ label: Artifact, version and runtime
+ description: Include JDK and container/framework versions when relevant.
+ validations:
+ required: true
+ - type: textarea
+ id: behavior
+ attributes:
+ label: Expected and actual behavior
+ description: Name the method/tag and parser context; use harmless placeholder data.
+ validations:
+ required: true
+ - type: textarea
+ id: reproduction
+ attributes:
+ label: Minimal non-sensitive reproduction
+ description: Include commands or a small example, and relevant sanitized diagnostics.
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..4a9aa0c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Report a suspected vulnerability privately
+ url: https://github.com/OWASP/owasp-java-encoder/security/policy
+ about: Do not put vulnerability details or proofs in public issues or pull requests.
+ - name: Read the output-context guide
+ url: https://github.com/OWASP/owasp-java-encoder/blob/main/docs/contexts.md
+ about: Choose an encoder for the parser receiving the value.
diff --git a/.github/ISSUE_TEMPLATE/context.yml b/.github/ISSUE_TEMPLATE/context.yml
new file mode 100644
index 0000000..733e619
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/context.yml
@@ -0,0 +1,21 @@
+name: Output-context question
+description: Ask which documented API fits an ordinary output context.
+title: "Context: "
+body:
+ - type: markdown
+ attributes:
+ value: |
+ This is a public discussion. Suspected encoding bypasses or vulnerabilities belong in [SECURITY.md's private channels](https://github.com/OWASP/owasp-java-encoder/security/policy).
+ - type: input
+ id: version
+ attributes:
+ label: Artifact and version
+ validations:
+ required: true
+ - type: textarea
+ id: context
+ attributes:
+ label: Surrounding syntax and question
+ description: Show a harmless placeholder, the template/framework and the parser receiving it. Explain any automatic escaping.
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml
new file mode 100644
index 0000000..ceee5b3
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature.yml
@@ -0,0 +1,22 @@
+name: Scoped feature proposal
+description: Describe a use case and compatibility tradeoffs before implementing it.
+title: "Proposal: "
+body:
+ - type: markdown
+ attributes:
+ value: |
+ Read the [context guide](https://github.com/OWASP/owasp-java-encoder/blob/main/docs/contexts.md) first. A proposal is not implementation approval. Report suspected vulnerabilities privately through SECURITY.md.
+ - type: textarea
+ id: use-case
+ attributes:
+ label: Use case and existing alternatives
+ description: Explain the parser context and why current APIs or standard libraries do not meet the need.
+ validations:
+ required: true
+ - type: textarea
+ id: compatibility
+ attributes:
+ label: Scope and compatibility
+ description: Identify public API, exact-output, Unicode/null, runtime and dependency effects. No implementation is required for triage.
+ validations:
+ required: true
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..9bbb568
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,13 @@
+## Change
+
+Describe the problem, resulting behavior and related issue. For suspected
+vulnerabilities, stop and use SECURITY.md's private reporting channels.
+
+## Compatibility and validation
+
+Describe affected contexts, exact-output/API/dependency changes and migration
+needs. List the relevant commands/results and any checks you could not run.
+
+- [ ] I kept the change scoped and preserved relevant notices.
+- [ ] I checked documentation/changelog and tests for any behavior change.
+- [ ] This PR contains no credentials or private vulnerability evidence.
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..b20fda6
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,135 @@
+# Changelog
+
+Released entries are grounded in the linked immutable tags, GitHub release notes
+and retained README announcements. Dates below are GitHub publication dates in
+UTC where a release record exists; older announcement/tag dates are labeled.
+An open proposal is not a release. Historical tags, assets and signatures remain
+unchanged. [1.4.1 publication is pending on Central](releases/1.4.1.md).
+
+## Unreleased — 1.5.0
+
+Development builds use `1.5.0-SNAPSHOT`; this is not a published release.
+
+* fix: resolve ESAPI's reference encoder lazily for each delegated operation. Missing configuration no longer poisons adapter initialization; OWASP-backed operations remain usable, and delegation can recover when configuration becomes available in the same JVM. JSON methods retain upstream delegation and null behavior [#165](https://github.com/OWASP/owasp-java-encoder/pull/165).
+
+* fix: the ESAPI adapter's `encodeForURL` now encodes individual URL components with UTF-8, including reserved delimiters and literal `+`, instead of preserving whole-URI delimiters. Spaces remain `%20`, null remains the string `"null"`, and unpaired surrogates remain `-`. See the [migration guide](esapi/README.md#url-encoding-migration-in-15-unreleased) for output changes, form-encoding differences, and the retained quoted HTML/CSS/JavaScript contracts [#100](https://github.com/OWASP/owasp-java-encoder/issues/100).
+* feat: all four `forJavaScript*` methods encode dollar sign (`$`) as `\x24`, backtick as `\x60`, and opening brace (`{`) as `\x7b` [#129](https://github.com/OWASP/owasp-java-encoder/issues/129). Escaping `{` prevents input after a trusted `$` from completing `${...}`. Encoded output now supports literal text in ordinary (untagged) template literals as well as single- and double-quoted strings. This changes the encoded output while preserving its decoded JavaScript string value. Tagged templates (including `String.raw`), `${...}` expression bodies, JSON, and script URLs are unsupported; each method's HTML context restrictions still apply.
+* fix: all four `forJavaScript*` methods escape unpaired UTF-16 surrogates as `\uXXXX`, preserving their JavaScript string values through UTF-8 serialization [#135](https://github.com/OWASP/owasp-java-encoder/issues/135), and escape DEL/C1 controls (U+007F to U+009F) as `\xNN` [#163](https://github.com/OWASP/owasp-java-encoder/issues/163). Valid surrogate pairs and other non-ASCII text remain unescaped except U+2028/U+2029. These are output-fidelity changes; NEL was already ordinary JavaScript string data.
+* feat: add `Encode.forJson` String/Writer methods, the `json` encoder context, and `forJson` tags and EL functions in both JSP and Jakarta tag libraries [#145](https://github.com/OWASP/owasp-java-encoder/issues/145). The caller supplies double quotes. Output uses RFC 8259 string escapes and also escapes HTML script delimiters. Java `null` becomes the text `null` (the JSON string `"null"` when quoted); unpaired surrogates use Unicode escapes and may not interoperate with every JSON consumer. Prefer a serializer for complete JSON documents. The ESAPI adapter retains its existing JSON delegation and null behavior.
+* feat: add `forXml11`, `forXml11Content` and `forXml11Attribute` tags and EL functions to the advanced JSP and Jakarta taglibs, and `forXml11` to the basic taglibs [#131](https://github.com/OWASP/owasp-java-encoder/issues/131).
+* deprecation: `Encoders.URI` and both `ForUriTag` classes are now deprecated like `Encode.forUri`, whose Javadoc now says what to use instead; the `forUri` TLD descriptions warn about double encoding, the adapter builds show deprecation call sites, and the README has a [forUri migration section](README.md#migrating-from-foruri) [#130](https://github.com/OWASP/owasp-java-encoder/issues/130).
+* fix: the JSP, Jakarta and ESAPI bundles now declare the core versions they need (`[1.5,2)` for the tags, which call `Encode.forJson`; `[1.4.1,2)` for ESAPI) and the JSP API ranges they support, instead of unversioned imports that could wire to an older core and fail when a tag ran. Bundle symbolic names are now declared explicitly and unchanged [#137](https://github.com/OWASP/owasp-java-encoder/issues/137).
+* fix: `forHtmlUnquotedAttribute` now replaces U+0085 (NEL) with a hyphen like the other C1 control characters, instead of emitting `
`, which HTML5 parsers decode as U+2026 [#136](https://github.com/OWASP/owasp-java-encoder/issues/136).
+* fix: the XML 1.1 encoders (`forXml11`, `forXml11Content`, `forXml11Attribute`) now encode U+0085 (NEL) as `
` and U+2028 (line separator) as `
`, so they are not normalized to a line feed [#136](https://github.com/OWASP/owasp-java-encoder/issues/136).
+* maintenance: clarify output-context contracts and expand XML 1.1 tests, fix clean reactor compilation, and remove the obsolete benchmark profile.
+
+### Build, compatibility and maintenance
+
+- Preserve original-JAR consumers on Java 8/11/17/21/25, explicit/automatic JPMS
+ and Felix R6/R8; add final TLD-surface/Writer contract checks (#162, #167).
+- Test packaged javax/Jakarta TLDs through isolated Tomcat/Jasper engines; retain
+ required real-browser and executable-WAR checks with the modernized optional
+ Boot 4.1.1 fixture (#179, #180).
+- Pin and guard Actions, add CodeQL/dependency submissions/Dependabot, isolate
+ Maven caches, and preserve required CI/security gates (#173, #177).
+- Include Java 9 descriptors in source attachments; normalize source metadata
+ and retain attribution (#184).
+- Retire the dormant Maven Site/OSS parent, adopt verified Maven 3.9.16 wrapper
+ and JDK 17 build policy, Checkstyle and measured unit coverage floors; isolate
+ signing/publishing tools, verify local bundles and measure reproducibility
+ (#185, #187). This does not change the Java 8 library runtime baseline.
+- Add release verification, historical key evidence, maintainer custody and
+ release-specific ESAPI guidance (#164, #171, #185). Historical signing-key
+ authorization gaps (#110) and Central access/custody work (#111) remain open.
+
+These items are merged through `3bd86250a9c9cd48577c3bf7fb9c46dbe91c1c90`.
+The [maintenance tracker](https://github.com/OWASP/owasp-java-encoder/issues/169)
+records PRs, tests and dispositions; it is not approval to publish 1.5.
+
+## 1.4.1 — 2026-09-26 UTC
+
+[Signed GitHub release](https://github.com/OWASP/owasp-java-encoder/releases/tag/v1.4.1)
+([tag created 2026-09-25 in America/Los_Angeles](https://github.com/OWASP/owasp-java-encoder/tree/v1.4.1)).
+**Central publication remains pending. Upgrade all four Java Encoder artifacts;
+versions through 1.4.0 are affected.**
+
+- Fix `EncodedWriter` context corruption during buffer overflow
+ ([GHSA-57jg-769q-93vh](https://github.com/OWASP/owasp-java-encoder/security/advisories/GHSA-57jg-769q-93vh)).
+- Fix insufficient-lookahead infinite loops in `EncodedWriter`
+ ([GHSA-q6jj-5396-8mq2](https://github.com/OWASP/owasp-java-encoder/security/advisories/GHSA-q6jj-5396-8mq2)).
+- Fix CSS String API maximum-output sizing for long U+2028/U+2029 runs
+ ([GHSA-p9ff-j89j-9xhx](https://github.com/OWASP/owasp-java-encoder/security/advisories/GHSA-p9ff-j89j-9xhx)).
+- Preserve Java 8 runtime, public method signatures, Maven and JPMS identities;
+ make adapter API dependencies transitively readable in module descriptors.
+- Pin the ESAPI adapter's default to 2.7.0.0 rather than a Maven version range.
+
+See the [full release record](releases/1.4.1.md) for affected entry points,
+coordinates, verification and publication status. Later 1.5 changes do not alter
+these retained artifacts.
+
+## 1.4.0 — 2025-11-17
+
+[Release and tag](https://github.com/OWASP/owasp-java-encoder/releases/tag/v1.4.0).
+Add XML 1.1 core APIs (#88); update tests and security documentation (#83, #86, #87).
+The ESAPI POM uses `[2.5.1.0,3)`; a temporary dependency pin controls resolution but
+**does not fix Java Encoder's security issues**. See the
+[1.4.0 migration guidance](esapi/README.md#temporary-esapi-pin-for-140-consumers).
+
+## 1.3.1 — 2024-08-20
+
+[Release and tag](https://github.com/OWASP/owasp-java-encoder/releases/tag/v1.3.1).
+Fix Java 8 `NoSuchMethodError` (#80) and add OSGi manifest entries (#82).
+
+## 1.3.0 — 2024-08-02
+
+[Release and tag](https://github.com/OWASP/owasp-java-encoder/releases/tag/v1.3.0).
+Raise the library minimum to Java 8; build with JDK 17 for test dependencies.
+Add historical automatic module names (#45), explicit Java 9 module descriptors
+via multi-release JARs (#77), and a separate Jakarta Servlet 5 adapter (#75).
+Update the ESAPI adapter (#76) and Javadocs. Javax and Jakarta remain separate
+artifacts with the same tag implementation package.
+
+## 1.2.3 — 2020-11-08
+
+[Release and tag](https://github.com/OWASP/owasp-java-encoder/releases/tag/v1.2.3).
+Make the manifest OSGi-compliant (#39) and support ESAPI 2.2+ (#37).
+This and earlier libraries retained the Java 5–7 runtime baseline, unlike 1.3+.
+
+## 1.2.2 — 2018
+
+[Tag](https://github.com/OWASP/owasp-java-encoder/tree/v1.2.2) created 2018-09-03;
+the retained README announcement is dated 2018-09-14. Documentation and licensing
+fixes. No separate GitHub release record exists at the 2026-09-26 inventory.
+
+## 1.2.1 — 2017-02-19 (tag/announcement)
+
+[Tag](https://github.com/OWASP/owasp-java-encoder/tree/v1.2.1).
+CDATA output no longer emits intermediate characters between adjacent CDATA
+sections; improve the Pages documentation. No separate GitHub release record
+exists at the inventory date.
+
+## 1.2 — 2015-04-12 (tag/announcement)
+
+[Tag](https://github.com/OWASP/owasp-java-encoder/tree/v1.2).
+Move the project to GitHub; the retained wiki also records removal of ThreadLocal
+use from development in February 2015. No separate GitHub release record exists
+at the inventory date.
+
+## Earlier announcements
+
+The [retained README](https://github.com/OWASP/owasp-java-encoder/blob/3bd86250a9c9cd48577c3bf7fb9c46dbe91c1c90/README.md#news)
+records 1.1.1 on 2014-01-30 (bug fix and ESAPI integration) and 1.1 on 2013-02-14
+(encoding refinements and JSP tags/functions). These are announcement dates,
+not independently established release timestamps; the old wiki dates the 1.1.1
+announcement differently. No corresponding GitHub tags/releases are present.
+The March 2014 documentation update is not a software release. Original Central
+artifacts and observed signatures are catalogued separately in [VERIFYING.md](VERIFYING.md).
+
+## Historical GitHub metadata disposition
+
+Checked 2026-09-26: GitHub releases exist for 1.2.3 through 1.4.1; titles vary
+between `Version 1.2.3` and `v...`, and 1.4.1 identifies itself as a security
+release. Keep those titles, dates and original text: they are unambiguous, and
+backfilling older entries would require inventing publication timestamps. This
+changelog supplies consistent navigation without rewriting history. Preserve
+1.4.0's dated upgrade supplement and 1.4.1's security/pending-publication notice.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..cd2d627
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,6 @@
+# Code of Conduct
+
+This OWASP project follows the [OWASP Code of Conduct](https://owasp.org/policy/code-of-conduct).
+The current Foundation policy defines expected conduct and its reporting process.
+For conduct concerns, use the reporting route in that policy. For a suspected
+software vulnerability, use the separate private channels in [SECURITY.md](SECURITY.md).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..a7a4b62
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,79 @@
+# Contributing
+
+Ordinary bugs, context questions, scoped proposals, tests and documentation fixes
+are welcome. Read the [context contracts](docs/contexts.md), [compatibility
+matrix](compatibility/README.md) and [Code of Conduct](CODE_OF_CONDUCT.md).
+Report suspected vulnerabilities **privately** through [SECURITY.md](SECURITY.md),
+not public issues, reproduction links or pull requests.
+
+## Build and check a change
+
+Use JDK 17, the committed Maven wrapper, and Python 3.8+ for repository checks.
+Libraries target Java 8; the build JVM is not Java 8. Docker is needed only for
+the optional local browser/WAR fixture, which remains a required CI job.
+
+```sh
+./mvnw -B -ntp clean verify
+python3 scripts/check-taglib-parity.py
+python3 -m unittest discover -s scripts/tests
+python3 compatibility/consumers.py prepare
+python3 -m unittest discover -s compatibility/tests
+python3 compatibility/consumers.py run --runtime 17 --java-home "$JAVA_HOME"
+./mvnw -B -ntp clean verify -PtestJakarta
+```
+
+Set `JAVA_HOME` to the JDK used for a consumer run. Prepare consumers only after a
+successful reactor verify and in an empty `target/compatibility`; `clean` removes
+old preparation output. To exercise one ESAPI matrix version:
+
+```sh
+./mvnw -B -ntp -pl esapi -am clean verify -Desapi.version=2.7.0.0
+```
+
+Other supported versions and their upstream security status are separate in
+[esapi/README.md](esapi/README.md). See [BUILDING.md](BUILDING.md) for the verified
+wrapper, Checkstyle's actual source scope/Java 17 exception, measured coverage
+floors and diagnostics. The legacy Maven Site and benchmark profiles are retired.
+Use fresh execution data when checking coverage; do not lower floors just to make
+a change pass. Tests and module descriptors have explicit style-check exceptions,
+not a claim that all sources are checked. Preserve original license notices.
+
+## Pull requests and review
+
+Keep the change focused and describe the trigger, resulting behavior, compatibility
+impact and validation. Output spelling matters: document new or removed escaping,
+null/Unicode changes, affected parser contexts and migration examples. Add behavior
+or parser regression tests for a contract change, including Writer boundaries where
+relevant. Keep javax/Jakarta sources and packaged TLDs in parity. Public API,
+bytecode, module/bundle identities and dependency scope changes need explicit review.
+Update the Unreleased changelog only for changes being delivered, not open proposals.
+
+The current rules require one approval, dismiss stale approvals after changes,
+require approval of the latest push and resolved conversations, and require the
+compatibility/CI gates plus Java, Actions and Python CodeQL checks on an up-to-date
+base. Named maintainers have an audit-visible **PR-only review bypass**; required
+CI/security checks have no bypass. CODEOWNERS requests review from verified
+maintainers; owner approval is not a separate enforced rule. AI review is useful
+but is not independent maintainer approval. See [CI/security operations](.github/CI_SECURITY.md).
+No DCO/sign-off requirement or new response-time guarantee is introduced here.
+
+Maintainers triage by reproducibility, affected context, security impact and
+compatibility cost. They may request a smaller case, consolidate duplicates or
+record a scoped deferral; a proposal is not implementation approval. This is a
+volunteer project without a public-issue response SLA. Discussions remains disabled;
+use the context-question form. Blank ordinary issues remain enabled for reports
+that do not fit a form. None of these public routes is for vulnerability evidence.
+
+## Funding
+
+The existing [funding authorization](.well-known/funding-manifest-urls), merged in
+[#157](https://github.com/OWASP/owasp-java-encoder/pull/157), points to
+[Jim Manico's maintenance funding manifest](https://manicode.com/funding.json).
+That manifest describes maintainer support through Manicode Security and its
+contact/payment channels; it is not an OWASP Foundation donation page. Separately,
+you can [donate to the OWASP Foundation](https://owasp.org/donate). Check the chosen
+recipient and current terms directly. Contributions of tests, reviews and docs
+are also valuable; funding does not determine review or security decisions.
+
+Release signing, access/custody and publication use [RELEASING.md](RELEASING.md)
+and [MAINTAINERS.md](MAINTAINERS.md), not the normal contributor build.
diff --git a/README.md b/README.md
index b0067a0..8aef3f1 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,37 @@
-OWASP Java Encoder Project
-==========================
+# OWASP Java Encoder
- [](https://opensource.org/licenses/BSD-3-Clause) [](https://javadoc.io/doc/org.owasp.encoder/encoder)
+
+[](LICENSE)
-Contextual Output Encoding is a computer programming technique necessary to stop
-Cross-Site Scripting. This project is a Java 8+ simple-to-use drop-in high-performance
-encoder class with little baggage.
+Contextual output encoding for Java 8+. Choose an encoder for the parser context
+receiving untrusted text: HTML, JavaScript, CSS, XML or a URL component. The core
+has no runtime dependencies; optional JSP, Jakarta and ESAPI adapters have their
+own dependency graphs. Encoding is one part of [XSS prevention][xss], alongside
+safe templates, URL validation and other application controls.
-For more detailed documentation on the OWASP Java Encoder please visit https://owasp.org/www-project-java-encoder/.
+**Upgrade all Java Encoder artifacts to 1.4.1. Versions through 1.4.0 are affected
+by the [security issues fixed in 1.4.1](releases/1.4.1.md#security-fixes).**
+Maven Central publication is still pending (checked 2026-09-26); the signed
+[GitHub 1.4.1 release][release] is available. Download, [verify](VERIFYING.md) and
+[install its retained artifacts](releases/1.4.1.md#verification) in your local or
+organizational Maven repository. Central alone cannot resolve 1.4.1. Do not use
+Central's affected 1.4.0 just because it is the latest version shown there.
-Project Leaders
----------------
+`main` is **unreleased 1.5.0-SNAPSHOT**. Its JSON API, JavaScript template support,
+XML 1.1 tag bindings and ESAPI URL change are described below with version labels;
+they are not features of the signed 1.4.1 release. See [CHANGELOG.md](CHANGELOG.md).
-- [Jim Manico](https://github.com/jmanico)
-- [Jeremy Long](https://github.com/jeremylong)
+## Start using the OWASP Java Encoders
-See [MAINTAINERS.md](MAINTAINERS.md) for responsibilities, signing-key custody,
-and recovery readiness.
+After installing the verified 1.4.1 artifacts, select the dependency you need.
+All four use group ID `org.owasp.encoder` and version `1.4.1`:
-Start using the OWASP Java Encoders
------------------------------------
-**Maven Central publication is pending.** Version 1.4.1 is available as signed
-artifacts from the [GitHub security release](https://github.com/OWASP/owasp-java-encoder/releases/tag/v1.4.1).
-Until Central publication completes, [download and verify those artifacts](releases/1.4.1.md#verification) and
-install them in your local or organizational Maven repository; the dependency
-examples below require that installation. Maven Central 1.4.0 remains affected.
-
-The core library's [Maven Central listing](https://central.sonatype.com/artifact/org.owasp.encoder/encoder)
-currently offers releases through 1.4.0.
-
-The JSP tag and EL function libraries have Central listings as well; their
-1.4.1 artifacts are available from the signed GitHub release while publication
-is pending:
-
-- [encoder-jakarta-jsp](https://central.sonatype.com/artifact/org.owasp.encoder/encoder-jakarta-jsp) - Jakarta Servlet 5.0+
-- [encoder-jsp](https://central.sonatype.com/artifact/org.owasp.encoder/encoder-jsp) - legacy `javax.servlet` API
-
-After installing the verified 1.4.1 artifacts, use these dependencies:
+| Artifact ID | Purpose and runtime dependencies |
+| --- | --- |
+| `encoder` | Core String/Writer API; no runtime dependencies |
+| `encoder-jsp` | Legacy `javax` JSP tags/EL functions; core plus container-provided JSP API |
+| `encoder-jakarta-jsp` | Jakarta JSP tags/EL functions; core plus container-provided Jakarta JSP API |
+| `encoder-esapi` | ESAPI `Encoder` adapter; core and ESAPI 2.7.0.0 with its transitive dependencies |
```xml
"); +Encode.forHtmlContent(out, userText); // Writer overload; no intermediate String +out.write("
"); ``` -To validate that the Jakarta JSP tags and EL functions work correctly, run the integration test: - -```shell -./mvnw verify -PtestJakarta +The equivalent String call is `Encode.forHtmlContent(userText)`. Callers supply +trusted surrounding syntax and attribute quotes. Encode raw data once, at the +output boundary; account for any escaping your template engine already performs. + +## Choose the output context + +| Destination | API and limits | +| --- | --- | +| HTML text, including textarea content | `forHtmlContent`; `forHtml` also covers quoted ordinary text attributes | +| Quoted HTML text attribute | `forHtmlAttribute`; not an event-handler expression or URL validator | +| One raw URL component | `forUriComponent`; assemble with trusted delimiters, validate the URL, then encode for the enclosing HTML attribute | +| JavaScript string | `forJavaScript`; supply single/double quotes. Ordinary untagged template literal text requires **1.5**. Never use in tagged templates, expression bodies, JSON or script URLs | +| JSON string content | `forJson` (**1.5**); supply double quotes. Prefer a serializer for a complete document | +| Quoted CSS string / CSS `url(...)` value | `forCssString` / `forCssUrl`; validate URLs and obey the method's surrounding-context rules | +| XML 1.0 text / quoted attribute | `forXmlContent` / `forXmlAttribute`; `forXml` covers both | +| XML 1.1 text / quoted attribute | `forXml11Content` / `forXml11Attribute` (core **1.4+**); requires an XML 1.1 document/parser, not HTML | +| XML CDATA / comment | `forCDATA` / `forXmlComment`; not HTML comments | +| Java source string literal | `forJava`; caller supplies quotes; unpaired surrogates may not compile | + +Every listed facade method has String and Writer overloads. The +[context guide](docs/contexts.md) explains nesting, null/Unicode behavior, +JavaScript variants, template boundaries, JSON and unsafe contexts. The +[Java/JSP examples](docs/usage.md) show complete surrounding syntax. + +Encoding does not sanitize HTML, validate input/URLs, serialize JSON documents, +perform SQL parameterization, or decode/canonicalize data. Use an HTML sanitizer +when markup must be allowed; use parameterized queries for SQL. See the +[OWASP Java security-library guide][java-libraries] for these distinct roles. + +## Taglib + +Taglib URIs are **identifiers**, not URLs that must open in a browser: + +| Adapter | Basic identifier | Advanced identifier | +| --- | --- | --- | +| Jakarta | `owasp.encoder.jakarta` | `owasp.encoder.jakarta.advanced` | +| javax JSP | `https://www.owasp.org/index.php/OWASP_Java_Encoder_Project` | Same identifier with `#advanced` appended | + +```jsp +<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> +<%@ taglib prefix="e" uri="owasp.encoder.jakarta" %> +${e:forHtmlContent(param.message)}
``` -The integration test requires a running Docker-compatible container runtime. - -Java 9+ Module Names --------------------- - -| JAR | Explicit JPMS Module | Automatic-Module-Name | -|---------------------|-----------------------|--------------------------| -| encoder | owasp.encoder | org.owasp.encoder | -| encoder-jakarta-jsp | owasp.encoder.jakarta | org.owasp.encoder.jakarta | -| encoder-jsp | owasp.encoder.jsp | org.owasp.encoder.jsp | -| encoder-esapi | owasp.encoder.esapi | org.owasp.encoder.esapi | - -The multi-release descriptors define the explicit Java 9+ module names. The -manifest names intentionally retain their historical values for consumers that -disable multi-release support or otherwise use automatic-module discovery. - -The adapter modules also require their public API dependency on the module path: - -| Adapter module | Required dependency module | Supported Maven artifact | -|---------------------------|----------------------------|-------------------------------------------------------| -| `owasp.encoder.jsp` | `javax.servlet.jsp.api` | `javax.servlet.jsp:javax.servlet.jsp-api:2.2.1` | -| `owasp.encoder.jakarta` | `jakarta.servlet.jsp` | `jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.0.0` | -| `owasp.encoder.esapi` | `esapi` | `org.owasp.esapi:esapi:2.7.0.0` | - -These dependencies are transitive in the module descriptors because their types -appear in the adapters' public APIs. The JSP and ESAPI dependencies are automatic -modules; use the original Maven artifact filenames so Java derives the module -names shown above. Servlet containers continue to provide the JSP APIs at runtime, -and classpath-based applications are unaffected. - -The ESAPI adapter's fixed dependency and tested compatibility policy are -documented in [esapi/README.md](esapi/README.md). - - -OSGi Bundles ------------- - -| JAR | Bundle-SymbolicName | Export-Package | Imports `org.owasp.encoder` | Imports API packages | -|---------------------|---------------------------------|--------------------------|-----------------------------|-------------------------------------------------------------| -| encoder | `org.owasp.encoder` | `org.owasp.encoder` | (none) | (none) | -| encoder-jsp | `org.owasp.encoder.jsp` | `org.owasp.encoder.tag` | `[1.5,2)` | `javax.servlet.jsp`, `javax.servlet.jsp.tagext`: `[2.0,3)` | -| encoder-jakarta-jsp | `org.owasp.encoder.jakarta-jsp` | `org.owasp.encoder.tag` | `[1.5,2)` | `jakarta.servlet.jsp`, `jakarta.servlet.jsp.tagext`: `[3.0,4)` | -| encoder-esapi | `org.owasp.encoder.esapi` | `org.owasp.encoder.esapi`| `[1.4.1,2)` | `org.owasp.esapi.*`: unversioned | - -The symbolic names are fixed; note that the Jakarta bundle's differs from its -`Automatic-Module-Name`. Core exports `org.owasp.encoder` at its release version. -The JSP and Jakarta tags require core 1.5 because they call `Encode.forJson`; the -ESAPI adapter only calls older methods, so its floor is the oldest supported core, -the 1.4.1 security release. Jakarta Pages 4 is not in the accepted range until -compatibility with it has been verified. ESAPI publishes no OSGi metadata: OSGi -users must wrap ESAPI and its dependencies as bundles themselves. The project's -tests supply the ESAPI packages from the framework host, which is not a statement -that upstream ESAPI supports OSGi. - -TagLib --------------------- - -| Lib | TagLib | -|---------------------|-----------------------------------------------------------------------------------------------| -| encoder-jakarta-jsp | <%@taglib prefix="e" uri="owasp.encoder.jakarta"%> | -| encoder-jsp | <%@taglib prefix="e" uri="https://www.owasp.org/index.php/OWASP_Java_Encoder_Project"%> | - -Every `Encode.forX(String)` context has a tag and an EL function in the advanced -taglib, except `forJava`: Java source generation is not a JSP output context. - -Migrating from forUri ---------------------- - -`Encode.forUri`, the `uri` context (`Encoders.URI`), `ForUriTag`, and the `forUri` -tag and EL function are deprecated. Percent-encoding a complete URI does not make an -untrusted URI safe: `forUri("javascript:alert(1)")` is returned unchanged. It also -always encodes `%`, so an already percent-encoded URI is double-encoded. - -- For an untrusted value inserted into a URL (a path segment, a query parameter name - or value, or a fragment), use `forUriComponent`: - - ```jsp - - ``` - -- For an entire untrusted URL, parse it with `java.net.URI`, allow-list its scheme - (for example `http` and `https`, rejecting a missing scheme unless relative URLs are - intended), enforce application-specific restrictions on its destination and - path, and then encode the whole value for the enclosing context. Parsing alone - does not establish safety: - - ```jsp - - ``` - -`forUri` is retained for compatibility in all 1.x releases. Whether 2.0 removes it is -tracked in [#142](https://github.com/OWASP/owasp-java-encoder/issues/142). - -The ESAPI adapter's `encodeForURL` changes separately in unreleased 1.5: it now -uses `forUriComponent`, escaping URL delimiters while retaining `%20` for spaces. -Pass raw component data, not a complete or already encoded URL. See the -[adapter migration and context contracts](esapi/README.md#url-encoding-migration-in-15-unreleased) -for differences from earlier adapter releases and ESAPI's reference form encoder. - -Development ------------ - -The OWASP Java Encoder project is a multi-module Maven project: - -```bash -$ ./mvnw verify +Use the javax identifier for a javax container. Tags use an empty body and a +required `value` attribute, for example `