Java's dynamic classloaders were one of it's original tantalising features. That you could have code from one place running somewhere else - "agents" could literally send their bytes to a device to execute there, run there and then erase themselves when they were done. It sounds crazy these days but it was all meant to be held together by the security model - built in at the core it was safe to let foreign byte code execute locally because the completely managed VM could enforce a security sandbox that allowed the code to do only exactly what it was meant to.
In some ways that is where this and all those features fell down ... if log4j had constrained those classes within a security sandbox it wouldn't matter what they did. But nobody understands or uses Java security permissions. The whole system is byzantine and drives people crazy whenever they do run into it. But if it had worked you could be asking the question, "why did log4j allow the permission for the remote code to do bad things" rather than "why was remote code allowed to execute".
In some ways that is where this and all those features fell down ... if log4j had constrained those classes within a security sandbox it wouldn't matter what they did. But nobody understands or uses Java security permissions. The whole system is byzantine and drives people crazy whenever they do run into it. But if it had worked you could be asking the question, "why did log4j allow the permission for the remote code to do bad things" rather than "why was remote code allowed to execute".