Infinite loops can only happen if (a) Observers are also Observable, (b) changes they observe can lead to changes in themselves, (c) the graph of observation is cyclic and (d) there is a kind of change which can end up triggering a change of the same kind. The ideal solution would be to design out the risk of infinite loops by ensuring one of those requirements is absent. If your current design makes all four true, see if you can change it to make one of them false.
The traditional uses for Observer-Observable are in layered architectures - for instance, where view-controllers observe model objects, or where event handlers observe GUI components - and here, the graph will not be cyclic, so there's no risk of infinite loop.
I should probably explain about point (d), about different kinds of changes. What i mean is that if you have a situation where, say, a UserInputEvent can trigger a ModelStateChangedEvent, and a ModelStateChangedEvent can trigger a WidgetUpdateEvent, which can't itself trigger anything, then even if the Observers form a cyclic graph, you can never get infinite loops, because there's only a finite number of stages in the sequence of events. Effectively, the events form an acyclic graph, even if the Observers don't. If, however, a ModelStateChangedEvent can trigger another ModelStateChangedEvent, then you have the risk of cycles.
If you really can't avoid the risk of cycles, then you can steal an idea from Jon Postel, and make every event notification carry an integer time-to-live counter. When an Observable broadcasts an 'original' event, meaning something that comes in from outside the network of Observers and kicks off a cascade of events inside it, it sets the counter to some suitable initial TTL value. When an Observable responds to an event by broadcasting another event, it would use a TTL one less than that of the triggering event. When an Observer gets a notification with a TTL of zero, it ignores it. This would prevent infinite loops, but would also prevent an Observer responding 'correctly' to some events, so it's an idea to be used with caution. I would strongly suggest that an event cascade hitting the TTL limit should be considered the result of a programming error, and should be logged and reported in the same way as you'd handle something like a NullPointerException or an assertion failure.