A quick note about how E2 works. Everything tangible to the Everything engine is a node. Users are nodes. Writeups are nodes. The things that we normally think of as 'nodes' are in fact 'e2nodes'; which are, of course, a type of node. Types of nodes, in fact, are themselves nodes. I think you're getting the picture by now: everything in Everything is a node. I'm a node, you're a node (if you've got an account here), nate's a node, Guest User is a node.

Nodes have their basic information stored in the node dbtable. They're identified by a completely unique identifier, the 'node_id' field of the node, and column in the database.

All very well and good. We have nodes. We can identify them by their node_id. Things like ownership of writeups, messages and membership of groups are all dictated by the node_id of the user's account, because that's the definitive way of identifying a node.

And this is what gets us into trouble.

In ecore, there's a handy dandy little function called updateNodeData. This function will manipulate fields of a node owned by the requesting user, in response to certain CGI parameters, which I'm not about to name, passed to the index.pl script. By default, it allows a user to manipulate any field of the node. This would, naturally, be quite a large security hole: you could, for example, change the owner of your bad writeups to someone else. You could change your username to be more or less anything you like. So to avoid this, sensitive fields aren't allowed to be written. These fields are named in a setting node, and access to any of these fields will be denied to anyone except members of gods. So, all is good. Right...?

(It's important to note, at this point, that the updateNodeData in the ecore used by Everything2 is very different from that used in the publicly available ecore's, so reasoning about one's behaviour from the other's is not exactly safe...)

One boring Friday night, I was poking around idly checking the sanity of things to make sure that things that shouldn't be writable weren't writable. Someone suggested that I check the node_id. The idea was ridiculous: you can't change the node_id of a node, it's unique. Even if the node_id field wasn't protected by the conventional mechanism, the database would refuse to update a node entry such that it violated the uniqueness constraint on node_id (the primary key of that table). It was inconceivable that it would work.

Logging in as a spare account, I entered the relevant runes to change the node_id of the account node to that of Guest User. If anything at all were to happen, I reasoned, that would at least be entirely harmless. The worst that could happen would be to clone Guest User into the old account node, so choosing the most harmless user account possible seemed a reasonable precaution.

I hit enter. Nothing seemed to happen. I checked the node_id of the homenode of the account... mysteriously, it seemed to have actually changed the node_id. Scratching my head, wondering how this had happened, I logged out... to no apparent effect. Yes, my theme and nodelets were still there, but the epicentre looked a lot like Guest User's.

Uh oh.

At about this time it started to occur to me what actually happened. The updateNodeData function didn't do exactly as I'd expected. It doesn't do an atomic database update. It takes the node data loaded from the database at the start of the pageload, and commits it to the database. And the only way it can work out where to put the node data is the node_id field in the copy of the node. Which we've just managed to mutate into Guest User's node_id. At no point was a duplicate node_id created, the new node's data was simply written over the data for the Guest User node. Pageloads for anyone not logged in to E2 are taken via the Guest user account. Which is identified via its node_id, so to all intents and purposes, huggles and Guest User were one.

Aha.

The obvious course of action was to create a new Guest User account to replace the old one and put things back pretty much the way they were. This duly done, I contacted an edev god with the intention of letting them know what was happening. Unfortunately, by this time, and before I'd adequately explained how I was able to more or less patch things up and how this wouldn't work for any other node, my accomplice had already pulled the same trick with nate's account.

At about this time, JayBonci appeared online, and I started explaining things to him; he promptly pulled the web servers down and started working out what had happened, and checking nothing nefarious had been done by the guest user account while it was masquerading as someone else.

After a brief amount of faffing around with IRC clients, we logged on to #everything and started trying to contact gods, begging forgiveness, and generally make a nuisance of ourselves. Nate duly appeared and forgave us, recognising our intentions as basically benign and realising the potential impact if the security hole had been discovered by more nefarious parties.

In summary, then: Jay is unquestionably the man, nate is about the coolest guy since Frosty the Snowman, and I couldn't be more regretful if I were Ronnie Corbett.

Oops.


As a note to Jay's root log, the Guest User node isn't fully restored. As a memento of the event, it's still noted as created on October 12th.