Skip to content
Security Article

The Client-Side Illusion: Lessons from the J&J Web App Vulnerabilities

Relying on frontend SSO flows without backend token validation is a recipe for trivial administrative takeovers.

Emeka Okafor
Emeka Okafor
Security Editor · Jun 25, 2026 · 5 min read
The Client-Side Illusion: Lessons from the J&J Web App Vulnerabilities

In security circles, there is a running joke that vulnerabilities fall into two categories. On one side, you have highly academic, multi-page mathematical proofs exposing flaws in deep cryptographic key derivations. On the other, you have "I told the computer I was an admin, and the computer believed me."

The disclosure of vulnerabilities in two Johnson & Johnson web applications, uncovered by security researcher Eaton, firmly belongs to the latter category. These applications, a college campus recruiting portal and an internal Audit Tracking Management System (ATMS), were compromised not through sophisticated zero-day exploits, but through a fundamental misunderstanding of where the security boundary lies in modern web architectures.

For developers building public-facing web services, these incidents serve as a stark reminder: frontend authentication is merely user experience. If your backend APIs do not actively validate the identity and permissions of the incoming request on every single call, your application is open to trivial bypasses.

The Campus Recruiting App: MSAL as UI Decoration

The first application analyzed was a "Campus Recruiting" website designed to manage university career fairs and student interviews. To restrict access to Johnson & Johnson employees, the site integrated the Microsoft Authentication Library (MSAL) into its frontend. When a user visited the /recruiter route, the frontend checked for an active MSAL session and, if absent, redirected them to the Microsoft SSO login page.

This looks secure to a casual observer, but it is entirely client-side security theater. The researcher bypassed this entire flow by modifying the client-side MSAL code in their browser to always return a mock "logged-in" account.

Once the frontend was tricked into rendering the recruiter dashboard, the underlying architectural flaw was exposed. The backend AWS APIs did not actually verify the MSAL Bearer token. Instead, the application relied on a hardcoded API key to authenticate requests to its backend. Because the frontend was already configured to use this static key for its API calls, bypassing the client-side redirect was all it took to gain full access to the data of nearly 1,000 students, including recruiter ratings and interview notes.

The Audit Tracking Management System: Local Storage Spoofing

The second target, the Audit Tracking Management System (ATMS), was an internal application used to manage audits across 20 associated companies, including LifeScan, Ethicon, and Janssen. This system was significantly more sensitive, containing internal meeting minutes, transcripts, and confidential data.

Like the recruiting portal, ATMS used MSAL for Microsoft SSO. However, the architectural flaws here went even deeper:

  1. Eager Bundle Delivery: When visiting the site, the entire React application bundle was downloaded to the browser before any authentication took place. By analyzing the downloaded JavaScript, the researcher mapped out the application's internal API endpoints.
  2. Unauthenticated Information Leaks: One of these discovered endpoints, getAllUsers, was completely unauthenticated. Querying it returned a list of 13.6k employee records, including names and Worldwide IDs (WWIDs).
  3. State Spoofing: The application's authentication logic checked local storage for specific session values to determine if a user was logged in. The researcher identified the system administrator's name from an unauthenticated help page, queried the getAllUsers API to retrieve their WWID, and patched the client-side code to write these administrator values directly into local storage.
  4. Unauthenticated Session Creation: To complete the spoof, the application needed a valid session GUID. The researcher found that the API endpoint responsible for generating these session IDs was also unauthenticated. By hitting this endpoint directly, obtaining a session GUID, and plugging it into local storage with a manual timestamp, the researcher bypassed the login redirect entirely and gained full administrative access to the system.

The Developer Angle: How to Audit Your Own Services

These vulnerabilities highlight a common failure mode in modern single-page applications (SPAs). Developers often treat the frontend router and client-side state as a secure perimeter. To ensure your applications do not fall victim to the same trivial bypasses, you must audit your code against three core principles.

1. Never Trust Client-Side State

Any code running in the user's browser can be modified, bypassed, or mocked. Local storage, session storage, cookies without the HttpOnly flag, and React state are completely under the control of the client.

If your backend API relies on a header like X-User-Role: Admin or reads authorization parameters from a client-controlled payload without verifying a cryptographic signature, it is vulnerable.

2. Enforce Server-Side Token Validation

If you use an identity provider like Microsoft Entra ID via MSAL, the frontend's job is solely to acquire the ID token or access token and attach it to outgoing requests. The backend's job is to validate that token on every single request.

Here is a conceptual example of how a backend middleware should validate an incoming Bearer token using standard JWT verification, rather than relying on static API keys or client-side flags:

const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
  jwksUri: 'https://login.microsoftonline.com/common/discovery/v2.0/keys'
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, function(err, key) {
    const signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

// Middleware to protect backend API routes
function requireAuth(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Unauthorized: Missing token' });
  }

  const token = authHeader.split(' ')[1];

  jwt.verify(token, getKey, {
    audience: process.env.CLIENT_ID,
    issuer: `https://login.microsoftonline.com/${process.env.TENANT_ID}/v2.0`
  }, (err, decoded) => {
    if (err) {
      return res.status(401).json({ error: 'Unauthorized: Invalid token' });
    }
    
    // Attach user context to the request
    req.user = decoded;
    next();
  });
}

If the Campus Recruiting app had implemented this validation instead of relying on a static AWS API key shared by all clients, the client-side MSAL bypass would have failed immediately at the API boundary.

3. Implement Code-Splitting for Sensitive Routes

Do not ship administrative routing logic, API endpoint lists, or sensitive UI components to unauthenticated users. If your entire React or Vue bundle is served statically to anyone who hits the landing page, you are handing attackers a roadmap of your attack surface.

Use dynamic imports and code-splitting to ensure that administrative dashboards and their associated API configurations are only loaded after a valid session is established.

// Avoid importing admin components at the top level
// Instead, lazy load them conditionally
const AdminDashboard = React.lazy(() => {
  if (!userIsAuthenticated) {
    return import('./components/EmptyLanding');
  }
  return import('./components/AdminDashboard');
});

The Cost of Delayed Remediation

The timeline of these reports reveals another critical lesson: security is as much about organizational process as it is about code.

The researcher reported both vulnerabilities to the Johnson & Johnson Vulnerability Reporting Program on October 6, 2025. While the Campus Recruiting vulnerability was resolved within weeks, the highly sensitive ATMS vulnerability remained unaddressed for months. It was only after the researcher engaged a journalist in April 2026, leading to press inquiries, that the company finally patched the internal audit system.

For engineering teams, this highlights the necessity of a functional, responsive vulnerability disclosure pipeline. When external researchers report critical flaws, a breakdown in internal communication or a lack of clear ownership can turn a responsibly disclosed bug into an active, unpatched liability. If your organization has a security reporting endpoint, ensure that the incoming reports actually reach the engineering teams who have the context and authority to deploy a fix.

Sources & further reading

  1. Exploiting vulnerabilities in Johnson and Johnson web apps — eaton-works.com
  2. Exploiting vulnerabilities in Johnson & Johnson web apps | Lobsters — lobste.rs
  3. hckr news - Hacker News sorted by time — hckrnews.com
  4. The Brutalist Report — brutalist.report
  5. Vulnerabilities in Johnson Controls' exacqVision Web Service Expose Security Systems to Video-Stream Hijacking — nozominetworks.com
Emeka Okafor
Written by
Emeka Okafor · Security Editor

Emeka has spent over a decade tracking threat actors, vulnerability disclosures, and the evolving landscape of application security, bringing a sharp continent-spanning perspective to his reporting. He's known for translating dense CVE advisories into clear, actionable context that developers and security teams alike actually read.

Discussion 0

Join the discussion

Sign in or create an account to comment and vote.

No comments yet

Be the first to weigh in.

Related Reading