completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Windows, iframes & postMessage

Learn how popups, iframes, sandboxing, postMessage, origin checks, and clickjacking defenses let browser windows communicate safely.

By the end, you can
  • 01
    Open popups safelyOpen a popup only from a user click, handle a blocked popup, and explain what noopener does.
  • 02
    Use iframes safelySay what a page may do with an iframe from its own origin and from another origin, and why allow-scripts plus allow-same-origin is risky.
  • 03
    Check messagesSend data with postMessage, then check event.origin, event.source, and the data before acting on it.

Several windows, one careful page

A web app is not always one page in one tab. It often uses other windows too:

  • A popup: a new tab or window, for example for signing in.
  • An iframe: a box inside your page that shows another page, for example a payment form.
  • A sandboxed frame: an iframe with most of its powers turned off, for content you don't trust.

Each of these is a browsing context: a separate place where a page lives. Each one has its own window object.

The main idea of this lesson is: a reference is not permission. A reference is a variable that points at another window. Holding one doesn't mean you can look inside. The browser still decides what you may read, change, or send.

The browser decides with the same-origin policy from the CORS lesson. Two pages have the same origin when their scheme (like https), host, and port all match. Only then may one page freely read the other.

When one page opens a new one, the new page gets window.opener. That is a reference back to the page that opened it. An untrusted new page can use it to send your page to a fake login page. This attack is called reverse-tabnabbing.

The noopener option cuts that reference, so the new page sees null. For a link, write target="_blank" together with rel="noopener". That attribute does the same job for links as the noopener option does for window.open.

The table compares the two kinds of extra window. Each row is one question, answered for a popup and for an iframe.

Popup or iframe?
QuestionPopupIframe
How do you make one?Call window.open(), or use a link with target="_blank".Put an <iframe> element in the page.
Where does it show up?In its own tab or window, in most browsers.Inside the current page, like an image.
What is it often used for?Signing in with another site, print previews, extra tools.Maps, payment forms, videos, chat boxes, and code demos.
What is the safe habit?Open it from a click, check for null, and use noopener.Use sandbox, load only pages you need, and check every message.
Real-life analogyAn iframe is a window into a neighbor's house

Some windows in your house look into another room of your own house. You can reach through and move things. Other windows look into your neighbor's house. You can see that the house is there, but you can't reach in. If you want something from your neighbor, you knock and pass a note.

In real life: A window into another room of your own house
In JavaScript: A same-origin iframe: you may read and change it
In real life: A window into your neighbor's house
In JavaScript: An iframe from another origin: you can see it but not reach in
In real life: Knocking and passing a note
In JavaScript: Sending a message with postMessage

This lesson teaches five safe habits:

  1. Open a popup only when the user clicks.
  2. Treat a frame from another origin as closed.
  3. Send each message to one named origin.
  4. Check every message when it arrives.
  5. Stop other sites from putting your important pages in a frame.

window.open and popups

INTERACTIVE

A popup is a new tab or window. JavaScript opens one with window.open(url, target, features):

  • url is the page to load.
  • target is a name for the new window.
  • features is a text list of options, such as the size or noopener.

It returns a reference to the new window. But browsers have popup blockers. They usually allow a popup only when window.open runs right inside a user action, such as a button click. This is called a user gesture. A call from a timer or from page load is often blocked. Then window.open returns null.

Safe popup code has four steps:

  1. Open the popup from a click.
  2. Check whether you got null.
  3. Use only what the browser allows.
  4. Close the popup when you are done.
Protect a new tab from its openerPop out in the code editor (opens in a new tab)JavaScript
const link = document.createElement("a");
link.href = "https://news.example";
link.target = "_blank";
link.rel = "noopener";
console.log(link.rel);

const popup = { opener: null };
console.log(popup.opener);

Lines 1 to 4 build a link that opens news.example in a new tab, with rel="noopener". Line 5 prints noopener. Line 7 makes a stand-in object for a new tab opened with noopener. Its opener is null, so line 8 prints null.

Left, without noopener: a new tab from news.example has an arrow called opener pointing back to your page, so your page can be redirected. Right, with rel noopener: the same two windows, no arrow, and opener is null, so your page stays safe.no noopenernew tabnews.exampleopeneryour pagecan be redirectedrel="noopener"new tabnews.exampleopener = nullyour pagestays safe
Without noopener, the new tab can reach back through window.opener and send your page somewhere else. With it, opener is null.

The lab below opens about:blank. That is an empty page with the same origin as the page that opened it, so the lab may write into it. The lab writes a heading, reads the popup's closed property, and closes it. The second button opens a popup with noopener. It shows that window.open then returns null.

Popup lab: open, check, close
Open a popup from a clickPop out in the code editor (opens in a new tab)JavaScript
button.addEventListener("click", () => {  const popup = window.open("about:blank", "lessonPopup", "width=360,height=240");  if (!popup) return "blocked";  popup.document.write("<h1>Hello from the opener</h1>");  console.log(popup.closed);  popup.close();}); const safePopup = window.open("about:blank", "_blank", "noopener");console.log(safePopup);
Popup logopened by a click
  • Press a button. The popup opens because you clicked.
Try it yourself

Browsers usually allow this popup because window.open runs right inside a click handler. Code that tries later, without a click, is often blocked.

The popup is an empty about:blank page with this page's origin, so the lab may write into it. If your browser keeps a tab open after the demo, close it.
Links need the same habit

For a link that opens a new tab, write target="_blank" rel="noopener". Many browsers now add noopener to such links by themselves. Write it anyway. It tells the next reader that the new page must not control yours.

Iframes and same-origin access

An iframe element shows another page inside the current page. The page around it is called the parent. What the parent may do depends on the frame's origin:

  • Same origin: the parent may read and change the frame's DOM (its elements), call its functions, and use the same storage.
  • Another origin: the parent still gets a reference to the frame's window. But most reads through it throw a SecurityError.
Read text from a same-origin framePop out in the code editor (opens in a new tab)HTML
<iframe id="preview" srcdoc="<p>Preview</p>"></iframe>

const frame = document.querySelector("#preview");
console.log(frame.contentDocument.body.textContent);
console.log(frame.contentWindow === frame.contentDocument.defaultView);

Line 1 is an iframe. Its srcdoc attribute holds the frame's HTML right in the attribute. A page made this way has the same origin as the parent, so the parent may read it.

  • Line 3 finds the iframe element.
  • Line 4 reads the frame's text through contentDocument, the frame's document.
  • Line 5 checks that contentWindow, the frame's window object, is the window of that same document.

If src pointed to another origin, contentWindow would still exist. But contentDocument would be null, and reading the frame's document through its window would throw.

Left: your page holds an iframe from the same origin, and it can read the iframe's DOM. Right: your page holds an iframe from another origin. Reading its DOM is blocked, but postMessage still works.your pageiframesame origincan read its DOMyour pageiframeother originDOM read blockedpostMessage still works
Both pages hold an iframe. Your page may read the frame from its own origin. A frame from another origin is closed to it, except for messages.

The table sums this up. Each row is one kind of frame: what your code can usually do with it, and what it can't.

What a window reference lets you do
Kind of frameWhat your code can usually doWhat your code cannot do
An iframe from your own originRead and change its DOM, call its functions, and use the same storage.Get around the sandbox, if the frame has one.
An iframe from another originKeep a reference to its window. Call postMessage, focus, blur, and close. Read closed, length, and frames. Set location in limited ways.Read its DOM, cookies, storage, full URL, variables, or most properties.
A sandboxed iframe without allow-same-originUse only the powers its sandbox tokens turn on. Its messages show the origin "null".Act like a normal page from your origin.

A frame from another origin still allows a short list of things through its window reference:

  • Send it a message with postMessage.
  • Call focus, blur, or close.
  • Read a few simple properties: closed, length, and frames.
  • Set its location to load a new page, in limited ways.

It can't read the other page's DOM, cookies, storage, variables, or full URL.

Two pages on your laptop can have different origins

The browser doesn't care that both pages run on your laptop. If the scheme, host, or port is different, the origins are different. For example, http://localhost:3000 and http://localhost:4000 are two origins. The URL objects lesson shows how to read each part of a URL.

Frames can hold frames, so the windows on a page form a tree, like folders inside folders. Each window has names for the windows around it.

Find where this page sits among framesPop out in the code editor (opens in a new tab)JavaScript
const frame = document.querySelector("iframe");
console.log(window.parent === window);
console.log(window.top === window);
console.log(window.frames.length);
console.log(frame.contentWindow === window.frames[0]);
  • Line 1 finds the iframe element.
  • Line 2 checks whether parent, the window just outside this one, is this window itself.
  • Line 3 checks whether top, the outermost window, is this window itself.
  • Line 4 prints how many child frames this page has.
  • Line 5 checks that frames[0] is the same window as the iframe's contentWindow.

The table lists these names. Read each row as: this name, what it points to, and when you use it.

Names for the windows around you
NameWhat it points to inside a frameWhat you use it for
windowThis page's own window.Use this page's own tools and data.
parentThe window just outside this one. At the top, it is window itself.Talk to the page that holds this frame.
topThe outermost window.Find out whether this page is inside a frame.
framesA list of this page's child frames.Reach a child frame by number or name, when allowed.

On a page that is not inside a frame, window.parent === window and window.top === window are both true. Inside an iframe, parent is the page just outside it, and top is the outermost page. These names only point at windows. They don't get past the origin checks.

postMessage and origin checks

STEP THROUGH

Two windows from different origins can't read each other. They can still work together by sending messages. The sender calls otherWindow.postMessage(data, targetOrigin). A little later, the other window gets a message event. The event has three parts you will check:

  • event.data: a copy of what was sent.
  • event.origin: the origin of the page that sent it.
  • event.source: the window object that sent it.

targetOrigin is the origin the receiving window must have. If that window has moved to a page from another origin, the browser doesn't deliver the message.

Real-life analogypostMessage is passing a note through a mail slot

Anyone can push a note through your mail slot. So before you act on a note, you read the return address. You also check who handed it in. When you send a note, you write a name on the envelope. If someone else lives at the house now, the note is not delivered.

In real life: The note
In JavaScript: event.data, a copy of what was sent
In real life: The return address
In JavaScript: event.origin
In real life: The person who handed it in
In JavaScript: event.source
In real life: The name on the envelope
In JavaScript: targetOrigin

Sandboxed frames need extra care. A sandboxed frame is an iframe with the sandbox attribute, which turns off most of its powers. Without the allow-same-origin token, the frame gets an opaque origin: an origin with no name. Message events show it as the text "null".

You can't write an opaque origin as a targetOrigin. So to send to such a frame, you must use "*", which means "any origin". That makes the checks on the receiving side even more important.

Message lab: a trusted frame and a stranger frame
The parent's message handlerPop out in the code editor (opens in a new tab)JavaScript
const frame = document.querySelector("iframe");const trustedWindow = frame.contentWindow; window.addEventListener("message", (event) => {  if (event.origin !== "null") return;  if (event.source !== trustedWindow) return;  show("accepted", event.data);}); trustedWindow.postMessage({ kind: "ping" }, "*");
Two real framesorigin "null"

Press a button to send a message.

Try it yourself

The trusted frame is sandboxed without allow-same-origin, so its origin is the text null. This page's own origin doesn't match it, so that message is never delivered. Only * delivers it. Then the parent checks the origin, the source, and the data.

Both frames are built from fixed srcdoc HTML with sandbox=allow-scripts. The parent accepts a message only if event.source is the trusted frame.

The lab has two sandboxed frames made from srcdoc. Both have the origin "null". Only one is the trusted frame: its contentWindow is saved in trustedWindow. The stranger frame can send the same data, but it fails the event.source check.

Two sandboxed frames, trusted and stranger, both have origin "null" and both send kind ready to the parent page. The parent page checks event.source. The trusted message is accepted. The stranger message is rejected.trustedorigin "null"strangerorigin "null"acceptedrejectedparent pagechecks event.source
Both frames have the origin "null", so the origin check can't tell them apart. The parent also checks event.source, so only the trusted frame's message is accepted.

Step through the same checks below. Pick the trusted frame or the stranger, then watch lines 5 and 6 decide.

Step through the message checks
Step 0 of 6Ready
Your turn: follow the blue line

Pick the trusted frame or the stranger. Then step through the origin check and the source check.

Running in
  1. script
Next: line 1
const trustedFrame = "lesson-frame"; function receiveMessage(event) {  const originOK = event.origin === trustedOrigin;  const sourceOK = event.source === trustedFrame;  if (!originOK || !sourceOK) return "rejected";  return "accepted: " + event.data.kind;} receiveMessage(incomingEvent);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Pick which frame sends the message
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

The message data is copied with structured clone: the browser makes a full copy of the data for the other window. The two windows never share one object. Functions and DOM elements can't be copied, so you can't send them. The next lesson covers copying in detail. Here, the habit to learn is: check a message before you act on it.

Check the message's fields tooPop out in the code editor (opens in a new tab)JavaScript
function acceptMessage(data) {
  if (!data || data.type !== "cart-ready" || typeof data.id !== "number") return "reject";
  return "accept";
}
console.log(acceptMessage({ type: "cart-ready", id: 3 }));
console.log(acceptMessage({ type: "cart-ready", id: "3" }));
  • Line 2 returns "reject" unless type is "cart-ready" and id is a number.
  • Line 5 passes an id of 3, a number, so it prints accept.
  • Line 6 passes "3", a string that only looks like a number. typeof gives "string", so it prints reject.

The origin and source checks tell you who sent a message. This check makes sure the data is what your code expects.

Safe or unsafe message handling?
  • Checks event.origin and event.source before changing anything
  • Sends a secret token with targetOrigin "*"
  • Accepts only objects with type: "cart-ready" and a number id
  • Runs whatever command name arrives in event.data.action
  • Uses child.postMessage(message, "https://pay.example") for a payment frame
  • Accepts every message whose origin is "null"
Try it yourself
0 of 6 correct

Sort each handler. Look for four things: a named target origin, an origin check, a source check, and a check of the data.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Sandboxed frames

INTERACTIVE

The sandbox attribute starts an iframe with most of its powers turned off. An empty sandbox blocks scripts, forms, popups, and dialogs. It also takes away the frame's real origin.

You add powers back one at a time with tokens: words you list in the attribute. Each token turns one power back on:

  • allow-scripts lets scripts run.
  • allow-forms lets forms submit.
  • allow-popups lets the frame open popups.
  • allow-modals lets it show dialogs, such as alert.
  • allow-same-origin keeps the frame's real origin instead of "null".
Sandbox and allow control different thingsHTML
<iframe
  sandbox="allow-scripts"
  allow="fullscreen; payment"
  srcdoc="<p>Limited preview</p>"
></iframe>

Line 2 lets this frame run scripts, and nothing else from the sandbox list. Line 3 is a different attribute, allow. It is a permissions policy: it turns on chosen browser features, here full screen and payments.

The two attributes do different jobs. sandbox limits what the page may do. allow turns on browser features. So allow="payment" does not let a frame read the parent page.

Sandbox lab: rebuild the frame with different tokens
The frame reports what it may doPop out in the code editor (opens in a new tab)JavaScript
// The parent rebuilds the iframe with selected tokens.frame.sandbox = "allow-scripts allow-forms";frame.srcdoc = predefinedHtml; // Inside predefinedHtml:parent.postMessage({  scriptRan: true,  origin: self.origin,  canSubmitForms: sandbox.contains("allow-forms"),  canOpenPopups: sandbox.contains("allow-popups"),  canShowModals: sandbox.contains("allow-modals")}, "*");
Frame sandboxallow-scripts
script runsyes
reported originnull
forms allowedno
popups allowedno
modals allowedno
Try it yourself

Start with everything off. Then turn on only the tokens the frame really needs. Without allow-scripts, this frame can't run the script that sends its report.

The frame runs only fixed srcdoc HTML. Without allow-scripts, Chrome prints “Blocked script execution” in the console: that is the sandbox doing its job. Browsers differ a little on popups and dialogs, so the table shows what each token allows.
The dangerous pair

Be very careful with sandbox="allow-scripts allow-same-origin" when the framed page has the same origin as yours. Its scripts can run, and it keeps your origin. So a script inside it can reach your page and remove the sandbox. For content you don't trust, leave out allow-same-origin. Talk to the frame only with checked messages.

That's why the sandbox demo in the CORS lesson and the message lab here both use fixed srcdoc HTML with sandbox="allow-scripts". The code can run, but the frame keeps an opaque origin. Everything it says goes through a few checked messages.

Clickjacking: when the visual page lies

INTERACTIVE

Clickjacking tricks a user into clicking a button on another page. It is also called UI redressing. It doesn't read the other page. It works like this:

  1. The attacker puts an important page, such as a bank page, in an iframe on their own site.
  2. They make that frame invisible and show a harmless-looking decoy instead.
  3. They line up the bank's real button with the decoy's fake button.
  4. The user clicks the fake button, but the click lands on the real one.
Left: what you see, a video window with a Play button. It is the decoy. Right: what you click, a fake bank window with a Transfer 100 button, in a hidden frame. An arrow labeled your click goes from the video to the bank.what you seevideoPlaythe decoyyour clickwhat you clickfake bankTransfer 100hidden frame
You see the decoy's Play button. But a bank page in a hidden frame is lined up with it, so your click lands on Transfer.
Real-life analogyClickjacking is a clear sheet over a real button

Picture a clear plastic sheet laid over a real button. A Play button is printed on the sheet. You press Play, but your finger pushes the Transfer money button under the sheet.

In real life: The picture printed on the sheet
In JavaScript: The decoy page you see
In real life: The button under the sheet
In JavaScript: The real button in the framed page
In real life: Thinking you pressed Play
In JavaScript: The user sees only the decoy
In real life: Actually pressing Transfer
In JavaScript: The browser sends the click to the framed page

In the lab, a decoy covers a fake bank frame. Lower the decoy's opacity to see the page hiding behind it.

Clickjacking lab: uncover the hidden page
A decoy over a framed pagePop out in the code editor (opens in a new tab)HTML
<iframe title="fake bank" sandbox srcdoc="...bank button..."></iframe><div class="decoy">  <p>Looks like a video player.</p>  <button>Play</button></div> /* Lower the decoy opacity to reveal the hidden frame underneath. */
Two layers96% decoy

Video preview

You see the decoy, but another page can sit behind it.
Try it yourself

At high opacity you see only a harmless video decoy. Lower it, and the fake bank page behind it shows through. The real defense is a header sent by the bank's server, not a script on the bank's page.

The bank is fake: fixed srcdoc HTML in a sandboxed frame. No money, network, or outside page is involved.

The fix belongs to the important page, not to the user. The table lists the defenses. Each row says who sets the defense and what it does.

Clickjacking defenses that work, and one that doesn't
DefenseWho sets itWhat it does
X-Frame-Options: DENYThe serverNo site may show this page in a frame.
X-Frame-Options: SAMEORIGINThe serverOnly pages from the same origin may show it in a frame.
Content-Security-Policy: frame-ancestors 'self' https://partner.exampleThe serverLists exactly which sites may show the page in a frame. This is the newer way.
A script that tries to break out of the frameThe page's own JavaScriptDoesn't work reliably. The attacker's page can block, delay, or sandbox the script.
Headers that stop framing before any clickHTTP
// Response headers, sent before the page is framed
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'

A response header is a line of information the server sends along with the page. Line 2 tells the browser that no page may show this page in a frame. Line 3 says the same thing in the newer Content-Security-Policy way. The browser reads these headers before it shows the page, so it can refuse the frame before anyone clicks.

This lesson page doesn't send these headers, because it has no important buttons to protect. An admin site, an account settings page, or a payment page should send them. On this site, the admin pages send X-Frame-Options: DENY.

Where you will use this

You will meet these tools in everyday web work:

  • Signing in with another site. Open the sign-in site in a popup from a click. When sign-in ends, the last page in the popup sends one success message back to your page.
  • Payment forms. Show the payment company's page in an iframe. Send it setup data with its exact targetOrigin. Accept only messages from its origin and its window.
  • Content previews. Show a draft page in a sandboxed iframe, so it can't change the editor page. The preview sends messages for things like its height.
  • Live code demos. Run demo code in sandboxed srcdoc frames. The frame sends results back as messages, and the page checks each one.
A checklist for real projects
  1. Save the window you expect: the popup or the iframe's contentWindow.
  2. Send with an exact targetOrigin. Use "*" only for a frame with an opaque origin.
  3. On arrival, check event.origin, event.source, and the fields of event.data.
  4. Ignore messages you don't know. Don't throw an error from the message handler.
  5. Protect important pages with X-Frame-Options or CSP frame-ancestors.

Common misconceptions

"I have a reference to the window, so I can read it."

Not if it has another origin. The reference allows only a few things, mainly postMessage. Most reads are blocked.

"Checking the origin is always enough."

Every frame with an opaque origin shows "null". One page can also hold several frames from the same origin. So check event.source too.

"Sending with targetOrigin "*" is always unsafe."

Sometimes you need it, for a frame with an opaque origin. Then never send secrets with it, and check every message that comes back.

"A sandbox makes any iframe safe."

The tokens matter. allow-scripts together with allow-same-origin lets a same-origin page remove its own sandbox.

"A script on my page can stop clickjacking."

Not reliably. The attacker's page can block or sandbox that script. Use server headers: X-Frame-Options or CSP frame-ancestors.

Practice: safe windows and frames

6 EXERCISES
Exercise 1 · Warm-upChoose the target origin

A parent page wants to send a short message with no secrets to a sandboxed srcdoc frame. The frame's origin is "null". Which targetOrigin must the parent use?

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticePredict the check

    Read the code and predict the word it prints.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const trustedOrigin = "null";
    const trustedSource = "frame-a";
    const event = { origin: "null", source: "frame-b" };
    console.log(event.origin === trustedOrigin && event.source === trustedSource ? "accept" : "reject");

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeRead popup.closed

      This object stands in for a popup. What two values print, in order?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const popup = { closed: false, close() { this.closed = true; } };
      console.log(popup.closed);
      popup.close();
      console.log(popup.closed);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengePick a clickjacking defense

        Name one header or CSP rule that stops other sites from putting an important page in a frame.

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeReview the unsafe handler

          Find the security problem in this handler. Then type the risky pair of sandbox tokens from this lesson.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          window.addEventListener("message", (event) => {
            if (event.origin === "null") {
              runCommand(event.data.action);
            }
          });

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · PracticeCheck a cart message

            Write a small check for messages from a cart iframe. Accept { type: "cart-ready", id: 3 }. Reject a message whose id is the string "3".

            Starter codePop out in the code editor (opens in a new tab)JavaScript
            function acceptMessage(data) {
              if (!data || data.type !== "cart-ready" || typeof data.id !== "number") return "reject";
              return "accept";
            }
            console.log(acceptMessage({ type: "cart-ready", id: 3 }));
            console.log(acceptMessage({ type: "cart-ready", id: "3" }));

            Answer, then press Check. Spacing and letter case don’t matter.

              Quiz: check your understanding

              8 QUESTIONS

              Your score counts first tries. Every choice has an explanation, so read them even when you get it right.

              Lesson quiz · 8 questionsScore: first tries count
              1. Question 1 of 8After calling window.open, what should your code check first?

                Choose an answer to see the explanation.

              2. Question 2 of 8What does this message check print for the stranger frame?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                const trustedOrigin = "null";
                const trustedSource = "lesson-frame";
                const event = { origin: "null", source: "stranger-frame" };
                console.log(event.origin === trustedOrigin && event.source === trustedSource ? "accept" : "reject");

                Choose an answer to see the explanation.

              3. Question 3 of 8Why do you sometimes need targetOrigin "*" to send to a sandboxed srcdoc frame?

                Choose an answer to see the explanation.

              4. Question 4 of 8Which of these can you do with a window from another origin?

                Choose an answer to see the explanation.

              5. Question 5 of 8What is risky about sandbox="allow-scripts allow-same-origin" on a page from your own origin?

                Choose an answer to see the explanation.

              6. Question 6 of 8This object stands in for a popup. What does the code print?

                Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                const popup = { closed: false, close() { this.closed = true; } };
                console.log(popup.closed);
                popup.close();
                console.log(popup.closed);

                Choose an answer to see the explanation.

              7. Question 7 of 8Which defense against clickjacking works reliably?

                Choose an answer to see the explanation.

              8. Question 8 of 8What does window.top === window tell a page?

                Choose an answer to see the explanation.

              Key takeaways

              • Open a popup only from a user click. Check for null, and use noopener so the new page can't reach back.
              • Your page may read an iframe from its own origin. An iframe from another origin is closed, but you can still send it messages.
              • postMessage sends a copy of the data. It arrives a little later as a message event.
              • Before acting on a message, check event.origin, event.source, and the fields of event.data.
              • A sandbox turns off a frame's powers, and tokens turn them back on one by one. Don't give a same-origin page both allow-scripts and allow-same-origin.
              • Server headers stop clickjacking: X-Frame-Options and CSP frame-ancestors.

              One-liner.
              Windows and frames can work together safely: the browser limits what each may touch, and your code checks every message before it acts.

              Up next: Messaging & structured cloning.

              CompleteFrontend Clear concepts. Working examples.