I think I must be mis-understanding how your tables are constructed - I have constructed a similar setup here and that query only pulls out articles in both categories...
CREATE TABLE `articles` ( `artID` tinyint(3) unsigned NOT NULL auto_increment, `content` varchar(255) default '0', PRIMARY KEY (`artID`)) TYPE=MyISAM;
CREATE TABLE `cats` ( `catID` tinyint(3) unsigned NOT NULL auto_increment, `name` char(255) default '0', PRIMARY KEY (`catID`)) TYPE=MyISAM;
CREATE TABLE `articleRES` ( `linkID` tinyint(3) unsigned NOT NULL auto_increment, `artID` tinyint(3) unsigned default '0', `catID` tinyint(3) unsigned default '0', PRIMARY KEY (`linkID`)) TYPE=MyISAM;
INSERT INTO `articles` VALUES("1", "article1 - only games");
INSERT INTO `articles` VALUES("2", "article2 - only movies");
INSERT INTO `articles` VALUES("3", "article3 - both games and movies");
INSERT INTO `cats` VALUES("1", "games");
INSERT INTO `cats` VALUES("2", "movies");
INSERT INTO `articleRES` VALUES("1", "1", "1");
INSERT INTO `articleRES` VALUES("2", "2", "2");
INSERT INTO `articleRES` VALUES("3", "3", "1");
INSERT INTO `articleRES` VALUES("4", "3", "2");
SELECT
articles.content, cat1.name, cat2.name
FROM
articles, articleRES as artcatRES1, articleRES as artcatRES2, cats as cat1, cats as cat2
WHERE
artcatRES1.artID = articles.artID
AND
artcatRES2.artID = articles.artID
AND
artcatRES1.catID = cat1.catID
AND
artcatRES2.catID = cat2.catID
AND
cat1.name = "games"
AND
cat2.name = "movies"
AND
cat1.catID != cat2.catID;
ah - could have been the missing cat1.catID != cat2.catID that might have caused dups.
all this is assuming u know how many categories the article is in to begin with - that is how many times u'll have to link the articleRes/cat tables.