Security Guide
MCP server CSS display-mode media query security — consent hidden in standalone PWA where browser chrome is absent, display-mode:fullscreen removes all escape UI, browser-tab-only consent gate via display-mode:browser, JS matchMedia display-mode conditional disable
CSS @media (display-mode) distinguishes browser tab, standalone PWA, fullscreen, and minimal-ui contexts. Hiding consent specifically in standalone or fullscreen mode targets users who installed the app — they have no browser address bar, reduced navigation options, and are typically the most engaged users. These are high-value targets for a consent bypass.
CSS display-mode media feature — overview
@media (display-mode) accepts four values: browser (normal browser tab), standalone (installed PWA, no browser chrome), minimal-ui (minimal chrome — some navigation controls but no full toolbar), and fullscreen (no chrome at all, JavaScript Fullscreen API or PWA fullscreen manifest). Detection of which mode is active is reliable — Chrome, Safari, Firefox, and Edge all expose this correctly. Related: scripting, pointer, prefers-reduced-motion.
Attack 1: consent hidden only in display-mode: standalone
A consent button visible in a regular browser tab is hidden via display: none in standalone PWA mode. Users who installed the web app — and are therefore more invested in the product — never see the consent request. Browser auditors and security scanners testing in a normal browser tab see no problem.
/* Attack: consent visible in browser tab, hidden in installed PWA */
.consent-section {
display: block; /* shown in browser tab */
}
@media (display-mode: standalone) {
.consent-section {
display: none;
/* Standalone mode = installed PWA:
- No browser address bar
- No browser back button on iOS
- User is in a dedicated app window
- App store / home screen launch icon user
All of these users are excluded from consent.
Security auditors testing in a browser tab miss this entirely. */
}
}
// Detection: CSSOM scan for display-mode:standalone hide on consent elements
function auditDisplayModeStandaloneHide(consentEl) {
const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
const sheets = Array.from(document.styleSheets);
for (const sheet of sheets) {
try {
for (const rule of sheet.cssRules) {
if (rule.type !== CSSRule.MEDIA_RULE) continue;
const mq = rule.conditionText || rule.media.mediaText;
if (!/display-mode\s*:\s*standalone/.test(mq)) continue;
for (const inner of rule.cssRules) {
if (inner.type !== CSSRule.STYLE_RULE) continue;
if (!consentEl.matches(inner.selectorText)) continue;
const d = inner.style.display;
const o = inner.style.opacity;
const v = inner.style.visibility;
if (d === 'none' || o === '0' || v === 'hidden') {
console.warn('[SkillAudit] display-mode:standalone hides consent:',
d ? 'display:' + d : '', o ? 'opacity:' + o : '', v ? 'visibility:' + v : '',
'| targets installed PWA users (no browser chrome, harder to navigate away);',
'| selector:', inner.selectorText);
}
}
}
} catch (e) { /* cross-origin */ }
}
if (isStandalone) {
const cs = getComputedStyle(consentEl);
if (cs.display === 'none' || cs.opacity === '0') {
console.warn('[SkillAudit] consent element hidden in standalone PWA mode:', consentEl);
}
}
}
High-value target population: Installed PWA users have already committed to the product. They are less likely to open a separate browser, notice the hidden consent, and report it. Hiding consent in standalone mode is a targeted attack against the most engaged user segment.
Attack 2: display-mode: fullscreen — no browser chrome, no escape
Fullscreen mode via the JavaScript Fullscreen API or a PWA with "display": "fullscreen" in the manifest removes all browser chrome. No tab bar, no address bar, no back button. Consent hidden in fullscreen mode is especially opaque — the user cannot easily navigate to another tab to check, and may not realize they are in fullscreen mode.
/* Attack: hide consent in fullscreen — no chrome means no easy escape */
.consent-section { display: block; }
@media (display-mode: fullscreen) {
.consent-section {
display: none;
/* fullscreen: browser chrome completely absent.
User entered fullscreen via: document.documentElement.requestFullscreen()
or PWA manifest "display": "fullscreen".
No address bar to see the URL.
No tab strip to switch tabs.
User must press Escape or know the keyboard shortcut.
Consent bypass in this context is maximally concealed. */
}
}
Attack 3: browser-tab-only consent via display-mode: browser gate
An inversion of Attack 1: the consent section is hidden by default and only shown in @media (display-mode: browser). This is equivalent to Attack 1 in effect but is structured as a "show only in browser mode" gate rather than a "hide in standalone" rule. Both patterns achieve the same outcome but the "show in browser" pattern can look like a legitimate "we don't show consent modals in the app" design decision.
/* Attack: consent only shows in browser tab — not in installed PWA */
.consent-section {
display: none; /* hidden by default */
}
@media (display-mode: browser) {
.consent-section {
display: block; /* only shown in browser tab context */
/* Semantically identical to hiding in standalone:
Standalone users never see consent.
The "show only in browser" framing is easier to justify
as "intentional responsive design" to code reviewers. */
}
}
// Detection: display-mode gate patterns on consent elements
function auditDisplayModeGate(consentEl) {
let browserOnlyShow = false;
let standaloneHide = false;
let fullscreenHide = false;
const sheets = Array.from(document.styleSheets);
for (const sheet of sheets) {
try {
for (const rule of sheet.cssRules) {
if (rule.type !== CSSRule.MEDIA_RULE) continue;
const mq = rule.conditionText || rule.media.mediaText;
for (const inner of rule.cssRules) {
if (inner.type !== CSSRule.STYLE_RULE) continue;
if (!consentEl.matches(inner.selectorText)) continue;
if (/display-mode\s*:\s*browser/.test(mq)) {
if (inner.style.display === 'block' || inner.style.opacity === '1') browserOnlyShow = true;
}
if (/display-mode\s*:\s*standalone/.test(mq)) {
if (inner.style.display === 'none' || inner.style.opacity === '0') standaloneHide = true;
}
if (/display-mode\s*:\s*fullscreen/.test(mq)) {
if (inner.style.display === 'none' || inner.style.opacity === '0') fullscreenHide = true;
}
}
}
} catch (e) { /* cross-origin */ }
}
if (browserOnlyShow) console.warn('[SkillAudit] consent only shown in display-mode:browser — hidden in PWA standalone, fullscreen, minimal-ui; element:', consentEl);
if (standaloneHide) console.warn('[SkillAudit] consent hidden in display-mode:standalone (installed PWA); element:', consentEl);
if (fullscreenHide) console.warn('[SkillAudit] consent hidden in display-mode:fullscreen (no browser chrome); element:', consentEl);
}
Attack 4: JS matchMedia display-mode conditional consent disable
JavaScript can detect standalone mode via window.matchMedia('(display-mode: standalone)').matches or via window.navigator.standalone (iOS Safari). A script that detects standalone mode and replaces the consent button, disables its event handlers, or skips consent initialization entirely bypasses consent for all PWA-installed users. This avoids CSS auditing entirely.
// Attack: JS standalone check + consent skip
const isStandalone = window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true; // iOS Safari
if (isStandalone) {
// Skip consent initialization for installed PWA users
window.__consentGranted = true; // auto-grant
document.querySelector('.consent-section')?.remove();
}
// Or: listen for PWA launch (display mode change from browser → standalone doesn't happen mid-session,
// but this pattern appears in service worker activation hooks)
window.matchMedia('(display-mode: standalone)').addEventListener('change', e => {
if (e.matches) {
document.querySelector('.consent-btn')?.style.setProperty('display', 'none');
}
});
// Detection: JS display-mode matchMedia + consent manipulation
function auditDisplayModeJS() {
for (const script of document.querySelectorAll('script')) {
const src = script.textContent;
if (!src) continue;
const hasDisplayMode = /display-mode/.test(src) || /navigator\.standalone/.test(src);
if (!hasDisplayMode) continue;
const hasConsentManip = [
/consent.*granted|__consent/i,
/remove\(\)|replaceChild|removeChild/,
/display.*none/,
/skip.*consent|consent.*skip/i,
].some(p => p.test(src));
if (hasConsentManip) {
console.warn('[SkillAudit] script checks display-mode (standalone or navigator.standalone)',
'and manipulates consent — verify consent is not bypassed for installed PWA users;',
'script:', script.src || '(inline)');
}
}
}
Findings summary
SkillAudit audits all four display-mode attack patterns — standalone hide, fullscreen hide, browser-only gate, and JS matchMedia bypass. It checks both CSS CSSOM rules and inline script patterns. Run a free audit on your MCP server.