This “bleeding” is caused by a pixel color defined by a uv coordinates on a map is not the equivalent of an integer. In other words, if your map would be 4 pixels wide, where you would use it on 2 sides only, the first side would be 0-2 and 2-4. In uv values, 0-0.5 - 0.5 -1. Each side would get rendered perfectly. In a situation like yours, assuming you use a 512 map your problem is basically “170.6666”(512/3) on u axis.
For the mapping logic of your cube, the u axis of your map is representing 3 sides, and as we use power of 2 sizes, you will always get coordinates that point to somewhere inside of a pixel on the map at the edges. This pixel color will be shared on at least 2 sides.
“Is there a way to prevent this and guarantee sharp edges?”
You could loop over normals per side and down resize a bit so it fits per side on the map using integers or loop and alter the uv’s u’s. So you end up having a non shared coordinates on the u values representing the edges of a side. Of course, you must ensure that the edges vertices/uvs are not shared before doing this. If you don’t problem will remain.
Doing this cost very little time/effort to be done if you are familiar with the engine. Some do prefer to build the cube from 6 planes geometries or import a custom one remapped in external editors…