This occurs because the filtering is set to GL_LINEAR. Bilinear filtering will select the nearest four pixels and blend them using a weighted average. As Roquen said, the RGB is blended even if the adjacent pixels have an alpha of zero.
For example, this 32x32 grass tile is located at (1, 1) on the sheet.
We see bleeding when we scale up:
This is because when GL goes to sample the edge pixels of our grass tile, it blends the grass with adjacent pixels (magenta).
The solution is to use GL_NEAREST for our sprite sheet, which only picks the “nearest” colour and doesn’t blend adjacent pixels.
If the images don’t need to be tiled, we could instead simply pad our sprite sheets with some transparent white pixels.
What if you need GL_LINEAR, and your sprites need to be tiled? Even if you pad the sprites, you will end up with bleeding (whatever is behind our tiles will bleed through, as it appears in your first screen shot). One hack/solution to this is to pad our sprites with pixels taken from opposing edges. The top line of pixels taken from the bottom, the left line of pixels taken from the right, etc:
The result when scaled:
This problem may also manifest itself if you’re loading non-power-of-two textures with Slick/SlickUtil. In that case, Slick pads the extra dimensions (to make it power of two) with transparent black pixels. Therefore bleeding on the bottom/right edges may occur using GL_LINEAR, even if the scale is unchanged.
tl;dr - don’t use GL_LINEAR
Bleeding may also occur if you are using non-power-of-two texture regions (i.e. sprites), due to floating point inaccuracies. Ideally you should stick to power-of-two where possible.