
Hashify.me - store entire website content in the URL - kevinburke
http://hashify.me/IyBIYXNoaWZ5CgpIYXNoaWZ5IGRvZXMgbm90IHNvbHZlIGEgcHJvYmxlbSwgaXQgcG9zZXMgYSBxdWVzdGlvbjogX3doYXQgYmVjb21lcyBwb3NzaWJsZSB3aGVuIG9uZSBpcyBhYmxlIHRvIHN0b3JlICoqZW50aXJlIGRvY3VtZW50cyoqIGluIFVSTHM/XwoKIyMgRG9jdW1lbnQg4oaUIFVSTAoKSGFzaGlmeSBpcyBkaWZmZXJlbnQgZnJvbSB2aXJ0dWFsbHkgZXZlcnkgb3RoZXIgc2l0ZSBvbiB0aGUgV2ViIGluIHRoYXQgKipldmVyeSBVUkwgY29udGFpbnMgdGhlIGNvbXBsZXRlIGNvbnRlbnRzIG9mIHRoZSBwYWdlKiouCgpUaGUgYWRkcmVzcyBiYXIgdXBkYXRlcyB3aXRoIGVhY2gga2V5c3Ryb2tlIGFzIG9uZSB0eXBlcyBpbnRvIHRoZSBlZGl0b3IuCgojIyMgQmFzZTY0IGVuY29kaW5nCgpPbmx5IGEgdGlueSBmcmFjdGlvbiBvZiBhbGwgVW5pY29kZSBjaGFyYWN0ZXJzIGFyZSBhbGxvd2VkIHVuZXNjYXBlZCBpbiBhIFVSTC4gSGFzaGlmeSB1c2VzIFtCYXNlNjRdWzFdIGVuY29kaW5nIHRvIGNvbnZlcnQgVW5pY29kZSBpbnB1dCB0byBBU0NJSSBvdXRwdXQgc2FmZSBmb3IgaW5jbHVzaW9uIGluIFVSTHMuCgpUaGlzIHRyYW5zbGF0aW9uIGlzIGEgdHdvLXN0ZXAgcHJvY2VzczogW1VuaWNvZGUgdG8gVVRGLTggY29udmVyc2lvbl1bMl0gYXMgb3V0bGluZWQgYnkgSm9oYW4gU3VuZHN0csO2bSwgZm9sbG93ZWQgYnkgYmluYXJ5IHRvIEFTQ0lJIGNvbnZlcnNpb24gdmlhIFtgd2luZG93LmJ0b2FgXVszXS4KCiMjIyMgRW5jb2RpbmcKCiAgICA+IHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudCgnw6dhIHZhPycpKQogICAgIsODwqdhIHZhPyIKICAgID4gYnRvYSh1bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoJ8OnYSB2YT8nKSkpCiAgICAidzZkaElIWmhQdz09IgoKIyMjIyBEZWNvZGluZwoKICAgID4gYXRvYigndzZkaElIWmhQdz09JykKICAgICLDg8KnYSB2YT8iCiAgICA+IGRlY29kZVVSSUNvbXBvbmVudChlc2NhcGUoYXRvYigndzZkaElIWmhQdz09JykpKQogICAgIsOnYSB2YT8iCgojIyBVUkwgc2hvcnRlbmluZwoKU3RvcmluZyBhIGRvY3VtZW50IGluIGEgVVJMIGlzIG5pZnR5LCBidXQgbm90IHRlcnJpYmx5IHByYWN0aWNhbC4gSGFzaGlmeSB1c2VzIHRoZSBbYml0Lmx5IEFQSV1bNF0gdG8gc2hvcnRlbiBVUkxzIGZyb20gYXMgbWFueSBhcyAzMCwwMDAgY2hhcmFjdGVycyB0byBqdXN0IDIwIG9yIHNvLiBJbiBlc3NlbmNlLCBiaXQubHkgYWN0cyBhcyBhIGRvY3VtZW50IHN0b3JlIQoKIyMjIFVSTCBsZW5ndGggbGltaXQKCldoaWxlIHRoZSBIVFRQIHNwZWNpZmljYXRpb24gZG9lcyBub3QgZGVmaW5lIGFuIHVwcGVyIGxpbWl0IG9uIHRoZSBsZW5ndGggb2YgYSBVUkwgdGhhdCBhIHVzZXIgYWdlbnQgc2hvdWxkIGFjY2VwdCwgYml0Lmx5IGltcG9zZXMgYSAyMDQ4LWNoYXJhY3RlciBsaW1pdC4gVGhpcyBpcyBzdWZmaWNpZW50IGluIHRoZSBtYWpvcml0eSBvZiBjYXNlcy4KCkZvciBsb2
======
dpcan
I see this as a remarkable answer to the problem of needing to view a cached
version of the website.

For example, what if a URL were posted to Hacker News, but after the URL was a
?hasifyme=THEHASH, where THEHASH was the Hash of the website linked-to.

This way, if the URL could not be loaded because the server load was to high,
you could just forward the URL to Hashify.me and the cache of the plain text
from the website would still then be readable.

Boom, instant cache of the website content stored right in the URL!!!!

~~~
zipdog
Clever use. But do you think it would scale? Doesn't it rely on bit.ly and/or
hashify.me being able to convert the URL into a readable page?

~~~
ay
I am missing something. How is this dramatically different from passing around
the data: URIs ?

data:text/html;charset=utf-8,However,%20data%20URI%20does%20the%20same%20without%20the%20server.

Here is a self-containing cached document, for simple texts probably with a
better efficiency than base64.

EDIT: ah. The shorteners barf if you try to "shorten" the data URIs

~~~
th
Actually tinyurl will shorten it but your browser may not allow the redirect.
Chrome throws up an error page for security reasons:
<http://tinyurl.com/3maue6t>

~~~
ay
Ha, nice - I tried only goo.gl and bit.ly

With <http://preview.tinyurl.com/3maue6t> it works, btw.

Though, tinyurl still barfs when I try to shorten the data URI that
<http://software.hixie.ch/utilities/cgi/data/data> gave to me when I let it
grab the index of HN.

------
nrkn
Oh dear. This is like some kind of sick, twisted Rube Goldberg machine...

Take entire text of Bram Stoker's Dracula

Chunk into 123 parts

Data URI encode each part

Generate a TinyURL link for each data uri (thanks for having an API guys)

Embed the TinyURL links in the Hashify Markdown editor using object elements

Curses! Even just the objects takes it over the limit. It has to be done in
two parts. Create two Hashify pages.

Part 1:

<http://bit.ly/havNYE>

Part 2:

<http://bit.ly/feoYrR>

Works in Firefox and Safari. Chrome, Opera and IE9 don't like it.

~~~
delitescere
Here ya go mate, in one page:

<http://tinyurl.com/hashcula>

hashify allows style tags :-)

------
gojomo
With a name like 'Hashify', I'm surprised they don't also offer the option of
putting the content into the '#fragment' portion of the URL. Then, not even
the hashify.net site would need to receive and decode the full URL; they'd
just send down a small bit of constant Javascript that rebuilds the page from
the #fragment.

~~~
hashify
> they'd just send down a small bit of constant Javascript that rebuilds the
> page from the #fragment.

That's _exactly_ what the site does. Everything happens client-side. nginx
serves a single index.html for every request. ;)

~~~
gojomo
Then why put the encoded content in the /path-info rather than the #fragment?

~~~
AndyKelley
It looks nicer.

~~~
metamatt
And gratuitous roundtrips are fun, too :P

(You're uploading the data in order to then convert it client-side. Groxx
noticed this too: <http://news.ycombinator.com/item?id=2464347>)

------
danielsoneg
Oh, Bit.ly's gonna _Love_ you guys.

Seriousy, though - awesome hack.

------
Groxx
A fantastic abuse of technology. That's one heck of a URL.

~~~
random42
Why abuse?

~~~
Groxx
Because "URI" stands for "Uniform Resource Identifier" (or URL for "Locator"),
not "Resource". The intent is for it to be a pointer, not the value at the
location. And, if you were to use the URI as the content (instead of chunking
and shrinking it via Bitly), you'd be duplicating that content on _every_ page
that links to it. And in your browsing history, by merely viewing it.

edit: oooh, another thought: you're essentially uploading the content of the
page to view it.

~~~
pbhjpbhj
There's an interesting copyright question in there somewhere too. If the URL
for my document is the document then sharing the link is infringing my
copyright, or something.

~~~
chii
there is such a thing as fair use in copyright law (at least, in australia and
US and most major western states).

------
kwantam
Last week on a whim I whipped up a URL shortener that expires the forwarded
URL after one week[1]. Using that plus hashify, you can essentially make
expiring web pages.

[1] pygm.us

------
paolomaffei
"A hash function is any well-defined procedure or mathematical function that
converts a large, possibly variable-sized amount of data into a small datum"

Hashify is not really a hash, is it?

~~~
angusgr
encode.me & base64.me are taken, but encodify.me is not. Doesn't have the same
ring as hashify.me, though.

~~~
ajays
abuse.me may be a better alternative... ;-D

I love this little hack. Sure, it may have no practical purpose; but it gave
me great joy to see this. I'm still smiling.

------
antimatter15
I hacked together an encrypted (aes 256) read/write "database" once with the
bitty API as the persistence backend.

However, this site disappoints me, it doesn't seem to do anything other than
what a data URL can do, except it's vulnerable to downtime because of a
centralized website.

Edit: for those of you unfamiliar with what a data URL is. You an store a HTML
or image document using a URL like data:text/HTML;base64,hashifystuffhere

~~~
hashify
Markdown > HTML

Just sayin' ;)

~~~
Semiapies
Add the trivial step, then. Markdown to HTML, HTML to data URL.

Or just, you know, _email_ people the content if you can give them the same
data anyway.

------
powera
This is pointless. It's impossible to create two pages that link to each
other, for one. Also, as noted, most browsers won't allow URLs greater than 2k
in size.

~~~
petercooper
This research is a few years old but, hopefully, things should be even better
by now: <http://www.boutell.com/newfaq/misc/urllength.html> .. Safari, Opera,
and Firefox all go over 80k. I found another source for Chrome that says they
"could not find any limits on Chrome and Safari".

Nonetheless, it's tricky because you have no idea if proxies in the middle
will be able to cope, mobile clients, and all sorts of things.. so you're
right in the sense that it's pointless (if you want it to be universally
acceptable ;-)).

~~~
xorglorb
In my own (very imprecise) testing, Chrome seemed to freeze around 215k
characters.

I found that my web server started throwing 413s after only about ~30k
characters.

------
pedalpete
Clearly this is awesome, I'm curious as to what lead you to build it?
Understanding that you weren't solving a 'problem', but you've created
something really compelling here.

Care to give a peak into how you came up with it?

~~~
hashify
A month ago, all the developers in the office spent two days working on
interesting small projects, the idea being that at the end of that time we'd
have a bunch of cool shippable features. Though it was encouraged to work on
useful, sensible things, this was not a requirement.

Anyway, I felt great until 4pm on the Friday, when we presented our creations.
Afterwards, I felt flat (as one often does after meeting a deadline or
finishing a series of exams). I didn't want the excitement to end.

As I was walking home I had an idea. For some reason I wanted to share
thoughts in 72pt Helvetica. I didn't want to broadcast them (I was melancholic
after all), but I felt compelled to express them visually.

I began to think about how this might be done. The Web seemed like the obvious
platform. I wondered whether it could be done without a database. I remembered
something I had heard on a podcast about a site that allowed one play musical
notes on a computer keyboard, and would encode these in the URL for easy
playback.

This seemed a lot more interesting than sharing my moody thoughts, and now
that I had something cool to work on I no longer felt the need to do so
anyway.

I think I spent 40 hours working on it that first weekend (yes, I was
consumed). I truly believed that I could ship it before showering and leaving
for work on Monday! Doing so would have been a mistake – I'm pleased that I
spent several weeks ironing out the kinks and integrating with bit.ly and
Twitter.

------
jules
So in effect, you're using bit.ly as a webhost. Url shorteners might not be
completely useless after all.

------
shazow
Here's a Python shortcut:

Instead of...

    
    
        from base64 import b64decode
        b64decode(foo)
    

You can do...

    
    
        foo.decode('base64')
    

Encoding works too. As well as zip (foo.encode('zip')).

~~~
mahmoudimus
It is worth noting there's a difference in the base64.b64encode function, vs
the default MIME Base64 codec on strings[2].

Per RFC2045[1]:

    
    
        (Soft Line Breaks) The Quoted-Printable encoding
        REQUIRES that encoded lines be no more than 76
        characters long.  If longer lines are to be encoded
        with the Quoted-Printable encoding, "soft" line breaks
    

Due to the insertion of these soft-line breaks, encoding is not the same, as
you can verify yourself:

    
    
        import os
        import base64
        import unittest
    
    
        class Base64Test(unittest.TestCase):
    
            def test_long_string_base64_decoding_and_encoding(self):
                byte_seq = os.urandom(500)
                mime64_encoded = byte_seq.encode('base64')
                self.assertNotEqual(base64.b64encode(byte_seq), mime64_encoded)
                self.assertEqual(base64.b64decode(mime64_encoded),
                                 mime64_encoded.decode('base64'))
    
    
        if __name__ == '__main__':
            unittest.main()
    

Decoding, as you can see above, is fine. This makes a difference when encoding
a really long string in an HTTP header.

[1] <http://www.ietf.org/rfc/rfc2045.txt> [2]
[http://docs.python.org/library/codecs.html#standard-
encoding...](http://docs.python.org/library/codecs.html#standard-encodings)

------
iamwil
I wonder if the equivalent of a quine for this is possible.

------
yakto
Too bad IE gets unhappy after 2K
([http://stackoverflow.com/questions/417142/what-is-the-
maximu...](http://stackoverflow.com/questions/417142/what-is-the-maximum-
length-of-a-url))

~~~
ignifero
For some reason i always thought URLs have a max length of 1024. Is there
anything about it in the HTTP standard?

~~~
HelloBeautiful
There is no max length in the standard. Of course every browser has a max it
can handle. For IE it is 2000 characters.

------
riobard
What about gzipping the content first?

~~~
gojomo
...and with a large library of switchable preset dictionaries for common
document scenarios...

------
hElvis
I am just coding the same thing right now (began a week ago). Also had the
idea to use bit.ly as shortener (because of its api) and make use of multiple
shortened links to store the data. Right before looking at HN I was doing some
research for a good js compressing algo.

On the one hand i am a bit disappointed (that i am too late), but on the other
hand hashify.me is made far better I could make it. Great realisation.

~~~
hashify
It's interesting that you say that. For some reason I felt under immense
pressure to get this out quickly, but I wrote that off as paranoia (should've
heeded Kurt's warning).

Now that it _is_ out in the wild, I can't wait to see what people do with it
slash build upon it.

~~~
hElvis
Well, it really _was_ out before in many ways, but not in such a nice one
(formated html etc.). Btw, do you have a base64 online converter and read my
code six days ago? Just "kidding".

------
juskotze
embedded images works. what would this be the solution for?
[http://hashify.me/aW1hZ2Ugb3ZlciBoZXJlIDxpbWcgc3JjPSdkYXRhOm...](http://hashify.me/aW1hZ2Ugb3ZlciBoZXJlIDxpbWcgc3JjPSdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQURJQUFBQXlDQVlBQUFBZVA0aXhBQUFBQVhOU1IwSUFyczRjNlFBQUFBUm5RVTFCQUFDeGp3djhZUVVBQUFBZ1kwaFNUUUFBZWlZQUFJQ0VBQUQ2QUFBQWdPZ0FBSFV3QUFEcVlBQUFPcGdBQUJkd25McFJQQUFBQVVwSlJFRlVhRVB0MlVzT3d5QU1CRkI2LzNQMG5DbU9na1FqZmdiYkRJaElyTkl1bnNZMkpQbGNYM2U1SFM2QzdMRGNEb2k3cWc0RXJDUlBJbWdsZVJJNWlVZ1BDZWYzUWIvV0xxMEhzUzRrQWhCaVBVZ0NzQjZrZ0ZnamtRcmdUc1JmMk0xZVE5d0VVaUJQclJZRTlOUnFBVHdwaEViSFM2UUZrZmtOVG8rVUVGRXZ4Q25nSlZKRDFKS0NhUFpSeEhOMm0xdGFPVVJES2IxUDMzTWdRaW5FR0h1SUFzTCtMY29Jb3ZJY1k1ZUlJc0l1RVdXRURjUUFvUTh4UXN5REpBNTlmMGVQamhjVWVzMWUydXh5OXpvQVlTL1JnUmdqZEVwckFrSWVNZ2toQzVtSWtJUDBJT2cvQTgydGMvcE5RUlJHYkFrK1ByVjYwaEJNUW1iOGdpREdlZ1FJSVE4cDlZVkNPWTAvSVhMVFVFYjBKY0pGQ0kvWjNPVGlUeTN1cURWSWc1OElOdzBqQkgxVTRDWENTY01Rd1lOd0VCWjk0VE1nUUZodGlhQ1YxQXZSbmdoU0dna0VRWDVLWEV5c2NGd213QUFBQUFCSlJVNUVya0pnZ2c9PScgYWx0PSdFbWJlZGRlZCBJbWFnZScgLz4gcGFzdCBpbWFnZQ==)

------
bct
What are the differences between this and a data: URI? Just the shortener and
that it can use out-of-band Javascript for the editor?

------
mlinksva
Nice hack, though odd name given that no hashing occurs.

~~~
jerf
Technically, if you squint hard enough, and assuming that Bit.ly always
shortens the same URL to the same code (which on my brief testing it did when
I tried the same URL from two different browsers), a one-way hashing function
is being created from bit.ly shortened URLs -> the full "hashed" document.
Technically. It certainly lacks most of the usual properties we associate with
hash functions but the bare skeleton is sort of there. And there's no way to
feasibly reverse that hash function algorithmically short of keeping the
original input table and querying that, which is how Bit.ly of course works.

~~~
albertsun
bit.ly does not always shorten the same URL to the same code

------
sbierwagen
So it's a reimplementation of data URIs, except it depends on two different
sites being up and responding to replies, so it lacks even the tiny amount of
usefulness data URIs have?

I can't think of a single use case where you would go, "Ah ha! Hashify would
work perfectly for this!"

~~~
jamesgeck0
One site; once you have the URL you don't necessarily need Hashify to decode
it for you. Actually, it seems like Hashify is simple enough that it could be
made to work offline using HTML5 without much work.

------
Enideo
A similar technique is used already on the website <http://www.wondersay.com>
Here the URL path is the text to animate and the fragment hash stores the
settings. Bitly is also used to hide the contents of the URL (and hence the
messages).

This is clever, in that the entire content of the website is not stored in a
database, but in external links. Obviously the biggest problem with this
technique is having bots crawl your site, so Google's #! convention is used.

------
aj700
would be a good text "host" but needs clones, so that when it disappears in a
few years I can still easily convert my urls back into the document therein.
that's the one problem these text host sites have. they never last. this gets
around this by hosting nothing, merely converting, but still.

and using bit.libya. i dont trust it.

isn't this also somewhat censorship resistant. since the hashify url without
its bitly can be put anywhere on the web that is writable, thus making
multiple copies available in a covert way.

------
kqueue
This is going to break in cases where the request line grows above 8k-16k.
Many browsers/proxies implement limits on headers/request lines, for good
reasons.

It's a very cool idea though.

~~~
jurjenh
This is quite clearly covered in the actual document!

> For longer documents, Hashify splits the contents into as many as 15 chunks.
> The chunks are then Base64-encoded and sent to bit.ly in a single request.
> The bit.ly hashes contained in the response are then "packed" into a URL
> such as <http://hashify.me/unpack:gYi2Ie,g4fpte>. Finally, this URL is
> itself shortened.

~~~
cdawzrd
> as many as 15 chunks

Yes, 15 * 2048 = a 30k limit on document size

------
EGreg
So basically, the URLs are files, and copying/pasting them is like
copying/pasting encoded data. It is the same as data: urls actually, except
maybe for browser security, which is pretty irrelevant for this anyway.

Actually, now I am wondering if an iframe src could be a data: url in
browsers. If so, that could be interesting! Showing content without hitting
the server. Probably not though, because of cross-domain security again. Any
ideas?

------
mumrah
Alternatively, you can use the Data URI Scheme like so:

    
    
      >>> "<h1>Hello, World!</h1>".encode('base64').strip('\n')
      'PGgxPkhlbGxvLCBXb3JsZCE8L2gxPg=='
    

Paste this into your location bar:
data:text/html;base64,PGgxPkhlbGxvLCBXb3JsZCE8L2gxPg==

Works in Chrome 10.0

------
yalogin
What is the purpose of this? The URL is already pointing to the store - the
actual site which hosts the page. Instead now we have a shortened URL which
stores the document. So they just took away the distributed nature of the URL
and put it all in one store (bitly).

------
theoa
Hashify.me seems to be overloaded for the moment. Nevertheless a brilliant and
delightful concept!

~~~
hashify
> Hashify.me seems to be overloaded for the moment.

Here's what I'm seeing in my browser console:

{ "data": [ ], "status_code": 403, "status_txt": "RATE_LIMIT_EXCEEDED" }

I should have included appropriate error handling for this! Everything except
shortening continues to function, though.

------
Steve0
This reminds me of the old tiny-url file system:
[http://tech.slashdot.org/story/05/10/25/0350222/TinyDisk-
A-F...](http://tech.slashdot.org/story/05/10/25/0350222/TinyDisk-A-File-
System-on-Someone-Elses-Web-App)

------
rudenoise
Very cool idea, it's something I can think of a bunch of cool uses for. Will
definitely be looking into it.

One downside came when I tried bookmarking with Delicious (hit the url length
limit, truncation would break it). But great for shorter content.

~~~
hashify
Bookmark the bit.ly URL, perhaps?

------
DanWaterworth
This is sweet. It would actually be possible to create a database using bitly
entirely in javascript. It would be read-only for clients and read/write for
webservers. You could even make it ACID compliant. I might have a go.

------
brndnhy
Careful.

Apache responds with an HTTP code 414-Request URI Too Large once the URI
reaches around 8K in length.

Default limits exist in several load balancers as well.

------
prassarkar
Hashify + pen.io and you've got a great service.

Hashify gets a pretty UI. pen.io removes the need for a DB.

------
blantonl
I could see this as a very useful implementation for HTML5/Mobile Web sites.

Consider the user experience _for the target site_ on a mobile platform. You
have _already loaded the site_ on your mobile device before even taking
action, so when you click the link the response is much faster than requesting
the site at the click.

------
micheljansen
At my workplace, this completely freaks out our corporate proxy, so no go :(

------
measure2xcut1x
The client side shorten request to bitly.com exposes the bitly credentials.

~~~
yahelc
Par for the course in any JSONP/CORS implementation.

------
strayer
Isn't it a "page" or "document", and not a "website"?

------
aneth
How long before the bit.ly namespace is exhausted?

------
petegrif
extremely cool

------
codejoust
Finally, an easy and quick way to decode base64 hashes.

------
sweis
This is vulnerable to XSS:
[http://hashify.me/PGlmcmFtZSBzcmM9ImphdmFzY3JpcHQ6YWxlcnQoJ1...](http://hashify.me/PGlmcmFtZSBzcmM9ImphdmFzY3JpcHQ6YWxlcnQoJ1dlYWsgc2VjdXJpdHknKTsiPgoK)

~~~
Cushman
That's a feature. You can encode an entire webpage, including JavaScript, and,
yes, including alerts.

As long as they don't have user accounts or database access or such, XSS
doesn't let an attacker do anything meaningful. It's not weak security, it's
just how the site works.

Edit: To point out the obvious, your iframe trickery is not necessary. Script
tags are not escaped, nor are event attributes:
[http://hashify.me/PGRpdiBvbmNsaWNrPSJhbGVydCgnVGhpcyBpc25cJ3...](http://hashify.me/PGRpdiBvbmNsaWNrPSJhbGVydCgnVGhpcyBpc25cJ3QgcG9vciBzZWN1cml0eSwgaXRcJ3MgYSB3ZWJwYWdlIHdpdGggSmF2YVNjcmlwdC4nKTsiPkNsaWNrIGhlcmUuPC9kaXY+Cg==)

~~~
hashify
> That's a feature.

Agreed! One can always link someone to a static HTML page with
<script>alert('fu')</script> in the body, but no one would tag that "XSS".

Does hashify.me make it easier to send annoying alert messages to your
friends? Sure. Annoying, but no more harmful than sending them to the static
equivalent.

~~~
sweis
Fair enough. It's similar to embedding third-party gadgets for things like
iGoogle. However, in practice that content is sanitized.

Note there are risks to hosting arbitrary Javascript beyond stealing cookies.
For example, you can steal browser history, discover NAT IP addresses, scan
intranet ports, etc. Here's a presentation by Jeremiah Grossman covering some
of these attacks: [http://www.blackhat.com/presentations/bh-usa-06/BH-
US-06-Gro...](http://www.blackhat.com/presentations/bh-usa-06/BH-
US-06-Grossman.pdf)

Of course, attackers can host malicious content anywhere they control. I could
just as easily send someone a bit.ly link to a malicious site I control.

