The terminology a particular browser uses to describe addons is slightly unhelpful. Some browsers call some things addons, some browsers call some things extensions. Somebody at some point came up with the idea of naming temporary storage "cookies" after all and how useful is that as a name.
So an extension mechanism (as in any extension to the browser's functionality) works on two levels:
OS <--- Firefox <--- webpage containing something
Plugin API---Relevant part of webpage, like <embed>
OS <----- Plugin! like ns_flash.so or such like
Here, extensions are compiled to match firefox's extension architecture for this sort of thing. Firefox exposes a certain set of functions to allow the extension to control it in certain ways, but the extension can also ask the operating system to do things directly. If it is well behaved, it basically takes the relevant input (i.e. here's a
.swf file) and does whatever it needs to do ("firefox, in this box, please draw this video"). However, it could technically do anything your user can do, because firefox isn't stopping it.
As to why Firesheep must be compiled, this is because it depends on libpcap (or similar), which is about extracting information packets from "the wire" i.e. from a device that's receiving them. A wireless interface is particularly susceptible to this because many wireless adapters are omni-directional so any interface in the vicinity picks these packets up. Usually, your kernel (operating system) would drop packets not addressed to it, however, setting the interface to promiscuous mode is how you ask it not to.
libpcap does this for you and allows you to grab those packets. In order to do this, it needs direct (probably administrative/root) access to the OS.
Firesheep works entirely by analysing those packets, finding http ones that aren't encrypted, scraping them for login data then reporting it.
Now, back to the security risk from these plugins - it's fairly obvious, a plugin that works as native code (in firefox, a plugin, rather than an extension) can do whatever you the user can do (forget firefox)) so as Hendrik rightly puts it, if you ignore the big fat warning, that's a problem. An extension ought to be able to do limited damage.
Whilst we're here, the google chrome model is different again. Every application on a computer is comprised of processes and threads - in many oses threads are basically lightweight processes and share memory across the process and that is how you achieve concurrency, however, a single crashed thread brings down the entire process and any thread can technically alter the memory of another thread without restriction.
So google chrome works by creating processes for every unique domain you visit uniquely, acting as if you had a process per tab (for many use cases) and every running extension you use. Actually, you can also customise this to execute a process per tab, or just one process per domain regardless of the visits you make. So whereas in firefox you get:
In google chrome you get
Chrome master process
Chrome child process for security.stackexchange.com
Chrome child process for meta.stackoverflow.com
Chrome child process for flash
Now, each child process is heavily restricted. The standard way to create a process gives it by default whatever permissions the parent has (inheritence) but google chrome sets permissions explicitly. Child processes can only communicate with the parent process when they want to do something and any API calls they make to the OS are severely restricted by windows' own access control tokens. So the idea here is that a plugin ought, in theory, to only be able to do what it needs to.
That is very much the theory of google chrome's idea. In practise the design documents imply you have to pass
--sandbox-plugins i.e. I'm not currently sure to what extent sandboxing plugins is automatic and whether they all work correctly yet.