Okay, I see the problem. In the traditional model of credential caching, the upper layer checks the cache for a credential, doesn't find it, goes out and gets it, and puts it in the cache. In a concurrent scenario a few processes might write duplicate entries to the cache, but that's (hopefully) rare and pretty harmless, so under this model we don't need the ccache layer to do any duplicate suppression. During a TGS request the KDC might hand us a credential we didn't ask for, such as a referral or an alternate TGS cred. Caching these credentials breaks the model--since we never wanted these credentials at the upper layer, the upper layer never checks for them. That also calls into question the value of caching those unsolicited responses-- they won't be useful if the same higher-level operation is repeated (or even a similar one, such as a request resulting in a refferal to the same realm). They would only save a TGS request if an unrelated operation happens to ask for that cross-realm TGT principal. So I think my preferred solution for this scenario is to change get_cred.c not to cache answers it didn't ask for. (This unfortunately isn't quite as simple as removing code due to the current design of step_get_tgt(), but it shouldn't be too hard.) Handling duplicates inside the ccache layer has a few problems: * FILE ccaches are essentially append-only, so suppressing duplicates by removing the old entry can't be implemented efficiently in the most common ccache type. (Heimdal implements removal by overwriting selected parts of the cred entry so that it becomes invisible to traversal, but that doesn't prevent the ccache from growing unacceptably large.) * Suppressing duplicates by ignoring the new credential isn't the behavior we want for ccache config entries. We would ideally like to be able to change the value of config entries that already exist by writing a new credential entry, although that doesn't currently work (krb5_cc_get_config() stops when it sees the old entry). * Copying a moderately-sized ccache would become O(n^2) as we do a full read of the ccache for each entry. In your patch, you noted a krb5_cc_remove_cred() call inside krb5_cc_store_cred(). That is an accidental leftover; see http://krbdev.mit.edu/rt/Ticket/Display.html?id=7906