VYPR
Medium severity5.3NVD Advisory· Published Jun 2, 2025· Updated Apr 15, 2026

CVE-2025-48996

CVE-2025-48996

Description

HAX open-apis provides microservice apis for HAX webcomponents repo that are shared infrastructure calls. An unauthenticated information disclosure vulnerability exists in the Penn State University deployment of the HAX content management system via the haxPsuUsage API endpoint, related to a flat present in open-apis versions up to and including 10.0.2. This allows any remote unauthenticated user to retrieve a full list of PSU websites hosted on HAX CMS. When chained with other authorization issues (e.g., HAX-3), this could assist in targeted attacks such as unauthorized content modification or deletion. Commit 06c2e1fbb7131a8fe66aa0600f38dcacae6b7ac7 patches the vulnerability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@haxtheweb/open-apisnpm
<= 10.0.1

Patches

1
06c2e1fbb713

https://github.com/haxtheweb/issues/security/advisories/GHSA-fvx2-x7ff-fc56

2 files changed · +3 70
  • api/community/haxPsuStats.js+0 68 removed
    @@ -1,68 +0,0 @@
    -
    -// duckduckgo.js
    -// this is an example to fork from that uses common, simple conventions
    -// for getting data, validating data, and responding in a consistent way.
    -import { stdPostBody, stdResponse, invalidRequest } from "../utilities/requestHelpers.js";
    -
    -export default async function handler(req, res) {
    -  // destructing GET params after ? available in this object
    -  // use this if POST data is what's being sent
    -  let body = {};
    -  let q = null;
    -  if (req && req.query && req.query.q) {
    -    body = req.query;
    -  }
    -  else if (req.body) {
    -    body = stdPostBody(req);
    -  }
    -  // fallback support for post
    -  if (body && body.q) {
    -    q = body.q;
    -  }
    -  // need to know what we're searching for otherwise bail
    -  if (q) {
    -    // we import fetch just to simplify endpoint creation but its just fetch
    -    // standard response is how all transactions end
    -    // this will assume 200 response code unless defined otherwise
    -    // response data is passed in as searchResults here
    -    // if type is not set in the options, then it is assumed JSON response
    -    // and is added to a data param
    -    const searchResults = await fetch(process.env.HAX_STATS).then((d) => d.ok ? d.json(): {});
    -    searchResults.links = [];
    -    var linkResp = '';
    -    for (var i in Object.keys(searchResults.site_counts)) {
    -        var key = Object.keys(searchResults.site_counts)[i];
    -        let link = `<a href="https://oer.hax.psu.edu/${key.split('/')[0]}/sites/${key.split('/')[1]}" target="_blank">${key} (${searchResults.site_counts[key]})</a>`
    -        searchResults.links.push(link);
    -        linkResp += "\n\n<li>" + link + "</li>";
    -    }
    -    let headers = {
    -        cache: 86400,
    -        methods: "OPTIONS, POST, GET"
    -    };
    -    let returnData = searchResults;
    -
    -    if (body && body.raw) {
    -        headers.type = 'text/html';
    -        returnData = `<ul>${linkResp}</ul>`;
    -        res = stdResponse(res, returnData, headers);
    -    }
    -    else if (body && body.random) {
    -      // Generate a random index within the array's length
    -      const randomIndex = Math.floor(Math.random() * Object.keys(searchResults.site_counts).length);
    -      let randKey = Object.keys(searchResults.site_counts)[randomIndex];
    -      returnData = `https://oer.hax.psu.edu/${randKey.split('/')[0]}/sites/${randKey.split('/')[1]}`;
    -      res.redirect(307, returnData);
    -    }
    -    else {
    -      res = stdResponse(res, returnData, headers);
    -    }
    -  }
    -  else {
    -    // invalidate the response and provide a reason
    -    // this optionally takes in a status code otherwise default is 400
    -    // vercel will through a 500 if there was any bricking issue so we don't
    -    // need to throw that most likely
    -    res = invalidRequest(res, 'missing `q` param');
    -  }
    -}
    \ No newline at end of file
    
  • api/services/stats/haxPsuUsage.js+3 2 modified
    @@ -9,9 +9,10 @@ export default async function handler(req, res) {
       // process.env.HAX_STATS has our stats compiled by our staging system
       let data = await fetch(process.env.HAX_STATS).then((res) => {
         return res.json()
    -  });
    +  })
    +  // only return overall data
       if (data) {
    -    res = stdResponse(res, data || [], options);
    +    res = stdResponse(res, {overall: data.overall} || [], options);
       }
       else {
         res = invalidRequest(res, 'data from stats failed to load');
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.