By Jess


2010-04-19 18:00:09 8 Comments

Why does Google prepend while(1); to their (private) JSON responses?

For example, here's a response while turning a calendar on and off in Google Calendar:

while(1);[['u',[['smsSentFlag','false'],['hideInvitations','false'],
  ['remindOnRespondedEventsOnly','true'],
  ['hideInvitations_remindOnRespondedEventsOnly','false_true'],
  ['Calendar ID stripped for privacy','false'],['smsVerifiedFlag','true']]]]

I would assume this is to prevent people from doing an eval() on it, but all you'd really have to do is replace the while and then you'd be set. I would assume the eval prevention is to make sure people write safe JSON parsing code.

I've seen this used in a couple of other places, too, but a lot more so with Google (Mail, Calendar, Contacts, etc.) Strangely enough, Google Docs starts with &&&START&&& instead, and Google Contacts seems to start with while(1); &&&START&&&.

What's going on here?

6 comments

@Arnaud Le Blanc 2014-02-02 12:09:00

It prevents disclosure of the response through JSON hijacking.

In theory, the content of HTTP responses are protected by the Same Origin Policy: pages from one domain cannot get any pieces of information from pages on the other domain (unless explicitly allowed).

An attacker can request pages on other domains on your behalf, e.g. by using a <script src=...> or <img> tag, but it can't get any information about the result (headers, contents).

Thus, if you visit an attacker's page, it couldn't read your email from gmail.com.

Except that when using a script tag to request JSON content, the JSON is executed as Javascript in an attacker's controlled environment. If the attacker can replace the Array or Object constructor or some other method used during object construction, anything in the JSON would pass through the attacker's code, and be disclosed.

Note that this happens at the time the JSON is executed as Javascript, not at the time it's parsed.

There are multiple countermeasures:

Making sure the JSON never executes

By placing a while(1); statement before the JSON data, Google makes sure that the JSON data is never executed as Javascript.

Only a legitimate page could actually get the whole content, strip the while(1);, and parse the remainder as JSON.

Things like for(;;); have been seen at Facebook for instance, with the same results.

Making sure the JSON is not valid Javascript

Similarly, adding invalid tokens before the JSON, like &&&START&&&, makes sure that it is never executed.

Always return JSON with an Object on the outside

This is OWASP recommended way to protect from JSON hijacking and is the less intrusive one.

Similarly to the previous counter-measures, it makes sure that the JSON is never executed as Javascript.

A valid JSON object, when not enclosed by anything, is not valid in Javascript:

eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :

This is however valid JSON:

JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}

So, make sure you always return an Object at the top level of the response makes sure that the JSON is not valid Javascript, while still being valid JSON.

As noted by @hvd in the comments, the empty object {} is valid Javascript, and knowing the object is empty may itself be valuable information.

Comparison of above methods

The OWASP way is less intrusive, as it needs no client library changes, and transfers valid JSON. It is unsure whether past or future browser bugs could defeat this, however. As noted by @oriadam, it is unclear whether data could be leaked in a parse error through an error-handling or not (e.g. window.onerror).

Google's way requires the client library in order for it to support automatic de-serialization and can be considered to be safer with regard to browser bugs.

Both methods require server-side changes in order to avoid developers from accidentally sending vulnerable JSON.

@funroll 2014-03-15 01:47:22

OWASP recommendation is interesting because of its simplicity. Anyone know a reason Google's way is more secure?

@vaxquis 2014-04-12 15:54:40

I believe it isn't more secure in any way. Providing OWASP here seems a good enough reason for +1.

@Filipe Giusti 2014-07-09 18:49:03

What browsers in 2014 let you replace Array or Object constructor?

@Dorn 2014-08-28 15:44:28

How would the OWASP method prevent people from simply using a JSONP method to get the data? It seems to me Google's method prevents this by not serving a valid JSON object, whereas the OWASP method says to use a valid JSON object so it can't be executed as javascript.

@Kelsey Francis 2014-08-29 02:08:54

JSONP requires the server to participate, and since the point of JSONP is to allow cross-domain access to the data in question, I don't think the server would be concerned with preventing cross-domain access to that data.

@Kelsey Francis 2014-08-29 02:19:32

I supposed if you must use JSONP you could try to use CSRF tokens in some clever (probably insecure) way.

@Manngo 2015-11-08 10:59:26

It may be worth noting why returning an object literal fails the script tag or eval function. The braces {} can be interpreted as either a block of code or an object literal, and by itself, JavaScript prefers the former. As a block of code it is, of course, invalid. By this logic, I can’t see any foreseeable changes in future browser behaviour.

@oriadam 2015-12-06 17:55:13

I'm surprised they are not using a method of removing the first char: "a":1,"b":2} or 1,2,3] are not valid JS and never will be, and it's very easy to add the correct char according to the last one. Google and Facebook will save millions of TB bandwidth.

@oriadam 2015-12-06 23:06:28

Bad code is not enough becaues an attacker can also hijack the script-error hander of the browser (window.onerror) I'm not sure what is the behavior of onerror with syntax errors. I guess Google were unsure as well.

@gengkev 2016-02-19 02:39:01

If it's an API that requires authorization, another counter-measure (that you should be using anyway) is CSRF tokens. Without a valid CSRF token, the server can outright reject the attacker's request.

@user743382 2017-05-06 20:50:44

"A valid JSON object, when not enclosed by anything, is not valid in Javascript:" -- Except for the trivial case of an empty object ({}), which is a valid empty block as well. If knowing the object is empty may itself be valuable information, this might be exploitable.

@kmmbvnr 2017-05-29 02:59:49

Medium API always return a non-empty object, but still with the prefix. Ex: ])}while(1);</x>{'success': true, 'payload': {}} Anyone knows reasons for that?

@Arnaud Le Blanc 2017-10-20 09:26:31

@kmmbvnr: Mostly for the same reasons, this is a paranoid security measure: They do that just in case returning an object is not enough to protect from JSON hijacking with some past of future browser version, or some yet-to-discover context.

@iono 2019-04-21 15:00:01

Worth noting that as of ES7, { } now has two new functions: interpolated strings `Hi, ${user}` and destructured assignment: let { prop1, prop2 } = objThatContainsThoseKeys

@tonix 2019-05-04 23:21:52

Why not returing something like this? ()=>{return;({"sensitive_data": 123})}. Of course requires 15 additional bytes, but would not cause scary infinite loops and does not throw syntax errors. Or even ()=>({"sensitive_data":123}), the attacker's site won't be able to execute the arrow function anyway...

@Pointy 2010-04-19 18:02:48

Note: as of 2019, many of the old vulnerabilities that lead to the preventative measures discussed in this question are no longer an issue in modern browsers. I'll leave the answer below as a historical curiosity, but really the whole topic has changed radically since 2010 (!!) when this was asked.


It prevents it from being used as the target of a simple <script> tag. (Well, it doesn't prevent it, but it makes it unpleasant.) That way bad guys can't just put that script tag in their own site and rely on an active session to make it possible to fetch your content.

edit — note the comment (and other answers). The issue has to do with subverted built-in facilities, specifically the Object and Array constructors. Those can be altered such that otherwise innocuous JSON, when parsed, could trigger attacker code.

@Mark Amery 2014-01-17 09:39:17

This is only half an answer. If it weren't for the trick of overriding the Object and Array constructors, executing a valid JSON response as though it were JavaScript would be totally innocuous in all circumstances. Yes, the while(1); prevents the response from being executed as JavaScript if targeted by a <script> tag, but your answer doesn't explain why that's necessary.

@rjh 2010-04-19 18:11:41

It prevents JSON hijacking, a major JSON security issue that is formally fixed in all major browsers since 2011 with ECMAScript 5.

Contrived example: say Google has a URL like mail.google.com/json?action=inbox which returns the first 50 messages of your inbox in JSON format. Evil websites on other domains can't make AJAX requests to get this data due to the same-origin policy, but they can include the URL via a <script> tag. The URL is visited with your cookies, and by overriding the global array constructor or accessor methods they can have a method called whenever an object (array or hash) attribute is set, allowing them to read the JSON content.

The while(1); or &&&BLAH&&& prevents this: an AJAX request at mail.google.com will have full access to the text content, and can strip it away. But a <script> tag insertion blindly executes the JavaScript without any processing, resulting in either an infinite loop or a syntax error.

This does not address the issue of cross-site request forgery.

@Jakub P. 2013-02-03 01:43:47

Why doesn't the request to obtain this data require a CSRF-token instead?

@Pedro Felix 2013-02-03 18:26:38

Wouldn't returning an object containing the array, instead of the array directly, also solve the problem?

@King Julien 2013-02-04 08:27:14

Does for(;;); do the same job? I've seen this in facebook's ajax responses.

@Boushley 2013-02-05 02:36:58

@PedroFelix No, that wouldn't solve the problem since the same attacks mentioned in the post could still be performed. Overriding the accessor methods to retrieve the info.

@abraham 2013-02-05 05:12:13

@JakubP. Storing and maintaining CSRF-tokens at Google's scale requires a large amount of infrastructure and cost.

@bluesmoon 2013-02-05 06:10:02

@JakubP. anti-CSRF tokens mess with caching, and require some amount of cryptographic evaluation server-side. At Google scale, that would require a lot of CPU. This sort of offloads it to the client.

@Eric 2013-02-05 07:30:25

Salesforce.com also prepends AJAX responses with while(1);

@Alex Neth 2013-02-05 12:06:07

@JakubP Why use a CSRF token when there is a simple solution that requires no infrastructure, complexity, or implementation?

@dave1010 2013-02-05 13:01:27

Why the infinite loop instead of a simple syntax error (to save characters)? You could just start the file with ).

@Scott 2013-02-05 14:15:24

So are you saying that when Google gets the returned data response from their legitimate AJAX request, that they find/replace or use a regex to remove the while(1); ?

@Dave Van den Eynde 2013-02-05 14:42:15

I don't like tricks. Isn't this solved by always returning an object?

@matt b 2013-02-05 15:11:33

@DaveVandenEynde no, see the link about overriding the global Array constructor; the same thing can be done for the global Object constructor

@dan 2013-02-05 15:38:00

This solution seems a little overly complex...can't you prevent the attack by never returning JSON on an HTTP GET request?

@Dan 2013-02-05 19:53:02

This is to prevent XSSI not CSRF.

@cstrat 2013-02-06 08:17:43

If the script generating the JSON required a POST rather than a GET request - does that fully mitigate this risk??

@Chris Tonkinson 2013-02-06 18:42:00

From a security perspective, would an open block comment work just as well? (i.e. "/*")

@0xSina 2013-02-07 18:37:50

@dave1010 error still not good enough. You can still read the contents of script tag. while(1) will hang up the interpreter.

@Dave Van den Eynde 2013-02-10 14:40:35

@mattb I'm not convinced. You can't load an object literal via a script tag. It's why WCF and OData wrap arrays in an object with a 'd' property.

@Arnaud Le Blanc 2013-02-14 21:03:21

@Boushley: no, since it would be a syntax error ({ at statement level starts a block).

@Arnaud Le Blanc 2013-02-14 21:04:40

@rjh: since a top-level object literal is a syntax error; wouldn't returning objects instead of arrays fix the issue too ?

@silkfire 2013-06-14 11:24:11

What would prevent me to scrape the JSON response and then strip that while(); statement with a script language, and then eval() it? And don't I normally have to be logged in to a site to access this kind of sensitive JSON? Just wondering.

@MarioDS 2013-06-14 12:27:16

@silkfire the fact that cross-domain XHR doesn't work. The script tag is used purely to be able to send the request. So what happens is, the response is loaded and then run, but you cannot control anything in between.

@silkfire 2013-06-14 13:17:19

@MDeSchaepmeester No I mean, I can enter the URL in a browser and then see the results, i.e. the JSON is fully readable?

@MarioDS 2013-06-14 15:23:40

@silkfire if you have a login cookie for Gmail, you will see the full json for your details (contact list, etc). But the trick here is, that you run the page on the client of your victim. So the script tag sends a request to get whatever is in its src attribute, with the cookies of the victim. So, the response will contain the data for the victim, but your script is in control so you can do whatever you want with it.

@Danack 2013-06-17 00:52:48

@silkfire The hack to get at the data works by replacing the array constructor with one that sends the data to an evil server. Because the while(1) stops the eval from reaching the array, the hack doesn't work as the array constructor never fires. From the answer below ejohn.org/blog/re-securing-json

@mlhDev 2013-11-14 17:01:56

@arnaud576875 - I get what you are saying, but you can read the contents of script tags (this is how most client-side templating is done, e.g.). It's just that you can only read the local contents of the script tag - not remote content (fiddle).

@Arnaud Le Blanc 2013-11-18 09:52:03

@Matthew we are talking about cross domain data disclosure; obviously if the script is local, this make everything discussed here irrelevant.

@Michael Mior 2013-12-30 01:12:34

CSRF protection is still required for POST requests.

@mcv 2013-12-30 15:06:44

It seems to me a better way would be to let the server only send the JSON if the correct header has been set. You can do that in an AJAX call, but not with script tags. That way, the sensitive information never even gets sent, and you don't have to rely on browser-side security.

@Greg 2014-10-20 01:53:56

@mcv. Headers seem a good, standard solution indeed. But why "better" ? Maybe at Google's scale, even processing the headers is something to avoid if possible.

@mcv 2014-10-20 10:26:02

I think it's better not to send sensitive data at all, than to send the data while trusting the browser to be unable to handle it. Although in cases like these, some trust in the browser is unavoidable. In a completely compromised browser, nothing is safe, obviously.

@John Hascall 2015-05-27 15:20:19

@mcv If the content has been cached someplace, that won't be effective.

@Mo Valipour 2015-05-29 08:23:36

how about while(1) alert('go away hacker!'); ?

@Nick Coad 2015-06-11 04:00:10

@Valipour the person that would see your alert is not the hacker.

@DuckMaestro 2015-08-18 00:22:33

Is this still relevant today (2015)? All blog posts I can find on this talk about Firefox 3 and Chrome 2, and that the JS specification hole will/may change. Is this security still present today in 2015 browsers?

@pilau 2015-10-22 11:33:04

@DuckMaestro if you try function Array() { console.log('security breach!'); } on Chrome you'll get your answer

@ErikE 2015-11-03 01:07:24

This also applies to <img> tags, which aren't held to the same-origin policy.

@Luaan 2016-01-04 14:22:50

@mcv You're still relying on browser security, there really isn't a way around that - ultimately, the user is using the browser to access their data :) For example, your browser might allow arbitrary AJAX requests, in which case you won't even need this trick in the first place. As long as you keep using cookies for authentication, you absolutely must rely on the browser treating cookies in a secure way - this includes domain isolation and same origin policy. It's not the server that blocks that cross-site AJAX request - how would it even know it's cross-site without the browser?

@John D. 2016-03-15 19:29:21

@King Julien- yes, and they have the advantage of saving 1 byte per request!

@Jörn Berkefeld 2016-03-23 14:19:06

@mvc you are forgetting scale. for a small website it probably wont make a difference. when you process millions of requests like Google, you gotta consider offloading work to the client in order to save costs. Headers would have to be evaluated on the server-side

@Ravinder Payal 2016-08-03 16:18:41

What if some one loads that url in an IFRAME and then copy content of IFRAME ???????????

@Hereblur 2016-08-04 03:48:04

@RavinderPayal They can't. XSS protection not allow JS to read IFRAME's content from different domain.

@Ravinder Payal 2016-08-04 06:26:31

Which also implies that old Comet technology should be implemented on same domain......OK leave that..... Do browsers differentiate sub domains also......

@Legends 2017-01-04 15:46:42

Is this still relevant? As this issue relies on this exploit, which has been fixed a long time ago, like the answer I am commenting on.

@sscarduzio 2017-05-06 20:18:48

So if I visit a compromised page, Google drains my battery. I guess this is necessary due to the lack of a synchronous sleep() function in Javascript. i.e. while(1) sleep(Number.MAX_SAFE_INTEGER)

@Akash Kurian Jose 2017-05-07 03:38:58

@sscarduzio no it runs for a little while and throws an unresponsive script alert. Its up to the user to stop it.

@João Antunes 2017-05-07 11:25:21

Now I'm very curious how and if an IMG element can be used for this: i.e. if it's possible to insert the json call as an IMG and then​ read its contents.. @ErikE mentioned the while protects from IMG as well??

@ErikE 2017-05-07 14:17:48

@JoãoAntunes Look up Array constructor hijacking.

@Brandito 2018-02-26 04:49:24

@KingJulien Yeah, that's just another way to write a loop. Not sure which is better although I think while(1) is used more for readability reasons.

@Krishna Ganeriwal 2017-08-18 04:14:44

Since the <script> tag is exempted from the Same Origin Policy which is a security necessity in the web world, while(1) when added to the JSON response prevents misuse of it in the <script> tag.

@bdonlan 2009-05-16 02:08:49

This is to ensure some other site can't do nasty tricks to try to steal your data. For example, by replacing the array constructor, then including this JSON URL via a <script> tag, a malicious third-party site could steal the data from the JSON response. By putting a while(1); at the start, the script will hang instead.

A same-site request using XHR and a separate JSON parser, on the other hand, can easily ignore the while(1); prefix.

@Morgan Cheng 2009-05-16 02:36:05

I suppose the XHR can only be issued to same domain server with authentication. How can "other site" intercept the response? Can you give more details on how "other site" steal our data?

@Matthew Crumley 2009-05-16 03:31:20

Technically, a "normal" JSON parser should give an error if you have a prefix.

@Laurence Gonsalves 2009-05-16 04:22:09

Attackers would just use a plain old <script> element, not an XHR.

@bdonlan 2011-02-24 12:54:22

@Matthew, sure, but you can remove it before passing the data to the JSON parser. You can't do that with a <script> tag

@Matthew Crumley 2011-02-25 00:03:19

@bdonian: Of course. I was just being pedantic and wanted to make sure nobody got confused about JSON. I like the new wording a lot better :)

@Lionel Chan 2012-10-30 07:10:50

Thanks - do we have any proper terms to describe this kind of security measure? I have seen facebook using for(;;); in their calls. I suppose this is the same mechanism as well, but shorter alternative?

@Dennis G 2013-02-05 13:37:18

Are there any examples of this? Replacing the array constructor is referenced again, but that's a bug long fixed. I don't understand how one would have access to the data received via the script tag. I'd love to see a dummy implementation which works in recent browser.

@joeltine 2013-02-06 19:07:52

In John Resig's blog he mentions very old browsers. Does anyone know if this exploit is still a concern in today's modern browsers?

@user69173 2013-06-03 19:44:04

@joeltine, no, it's not. See stackoverflow.com/questions/16289894/… .

@Derek 朕會功夫 2014-01-23 02:23:12

If it's to prevent JSON hijacking, then would /*[...]*/ work too?

@Daniel Vassallo 2010-04-19 18:04:36

That would be to make it difficult for a third-party to insert the JSON response into an HTML document with the <script> tag. Remember that the <script> tag is exempt from the Same Origin Policy.

@Mark Amery 2014-01-17 09:37:33

This is only half an answer. If it weren't for the trick of overriding the Object and Array constructors, executing a valid JSON response as though it were JavaScript would be totally innocuous in all circumstances. Yes, the while(1); prevents the response from being executed as JavaScript if targeted by a <script> tag, but your answer doesn't explain why that's necessary.

@Ravinder Payal 2016-08-03 16:24:25

but how it will prevent iframes

@Suraj Jain 2018-06-03 14:59:17

Script tag is never exempt from same origin policy. Could you clear that up for me?

Related Questions

Sponsored Content

15 Answered Questions

[SOLVED] Creating a JSON response using Django and Python

  • 2010-03-11 19:40:35
  • Switch
  • 471626 View
  • 433 Score
  • 15 Answer
  • Tags:   python django json

16 Answered Questions

[SOLVED] What is JSON and why would I use it?

  • 2008-12-20 20:19:11
  • Ben
  • 512468 View
  • 527 Score
  • 16 Answer
  • Tags:   json

14 Answered Questions

[SOLVED] Why Does OAuth v2 Have Both Access and Refresh Tokens?

13 Answered Questions

[SOLVED] Standard JSON API response format?

  • 2012-10-09 18:43:36
  • FtDRbwLXw6
  • 506417 View
  • 644 Score
  • 13 Answer
  • Tags:   json request response

9 Answered Questions

[SOLVED] Why does ++[[]][+[]]+[+[]] return the string "10"?

  • 2011-08-26 08:46:14
  • JohnJohnGa
  • 198117 View
  • 1617 Score
  • 9 Answer
  • Tags:   javascript syntax

4 Answered Questions

[SOLVED] Why does parseInt(1/0, 19) return 18?

5 Answered Questions

[SOLVED] JSON: why are forward slashes escaped?

  • 2009-10-16 21:54:18
  • Jason S
  • 166610 View
  • 355 Score
  • 5 Answer
  • Tags:   javascript json

2 Answered Questions

[SOLVED] Strange JSON response in Google Plus

Sponsored Content